turbolinks / turbolinks-ios

Native iOS adapter for building hybrid apps with Turbolinks 5
MIT License
880 stars 92 forks source link

visitRendered is called twice after initial request #165

Open gearoidoceallaigh opened 4 years ago

gearoidoceallaigh commented 4 years ago

It looks as though visitRendered is being triggered twice after an initial load when a page is loaded using the Turbolinks.visit method.

I've been able to reproduce using a clean Rails 6 project and the a clean Turbolinks Demo app.

To reproduce:

  1. Create a new Rails 6 (I'm using 6.0.2) app and some new view/controller you can visit. Start the server.
  2. Download the turbolinks-ios library and run the TurbolinksDemo project.
  3. Update the URL in the iOS project to hit your local server.
  4. Open the web inspector in Safari and access the console
  5. Add a breakpoint to visitRendered in the injected script (user-script)
  6. Run Turbolinks.visit('/')
  7. visitRendered is triggered once (correctly)
  8. Run Turbolinks.visit('/') again
  9. visitRendered is triggered twice
  10. Interestingly, only one HTTP request is made.

This results in two visitableDidRender calls in the iOS app which is negatively impacting my application as I do some additional view controller configuration post render.

Would appreciate it if someone could try the above and report if they are able to reproduce.

gearoidoceallaigh commented 4 years ago

Looks as though the double rendering is triggered as a result of page caching.

The "fix" in this case:

  1. Add <meta name="turbolinks-cache-control" content="no-cache"> to the head
  2. visitRendered will only be triggered once

This makes sense as two (potentially) different DOMs are presented to the app. This is a bit confusing but I accept it's a sacrifice to put the "turbo" in "turbolinks" 🙂

It would be great if visitableDidRender had some way of discerning whether it was receiving a cached version of the page or not. In my case, I am looking for a meta which determines the user's session status and when caching is enabled, my app will initially receive a DOM which reflects the user being signed out.

I'll try setting this using document.addEventListener("turbolinks:before-cache", function() {

^ Unfortunately this didn't work.