Nuxt.js: Page dom refreshed Before transition

Created on 16 Oct 2018  ·  26Comments  ·  Source: nuxt/nuxt.js

Version

v2.3.4

Reproduction link

https://codesandbox.io/s/2j0y809j2p

Steps to reproduce

I am not sure if it is a bug or just my mistake. The reproduction simulate chaining a state with fetch, like in a app with axios.

  1. Run the example
  2. Click Start <- transition is ok
  3. Click Next 1 <- starts blinking
    etc

You will see a color blink. Because the store/page is refreshed before the transition starts.
So first the color is changing to new value, then the transition is starting.

Check the console output.

What is expected ?

afterLeave...
Before enter...
store.mutations #a40c82
---mounted
After enter...

What is actually happening?

store.mutations #a40c82
afterLeave...
Before enter...
---mounted
After enter...

Additional comments?

Thanks for help!

This bug report is available on Nuxt community (#c7989)
bug-report pending

Most helpful comment

Frustrating to see how bug reports are closing automatically.

All 26 comments

@pi0 Could you look at it?

Because now you are closing the reports without even checking it :(

Frustrating to see how bug reports are closing automatically.

Hi Guys, anyone can help with it?

Is it a problem with a nuxt lifecycle or with the vue-router? Could we do something about it? Thanks!
Ping @clarkdo @pi0

I think is is somewhat intended.

When the SSR request happens, asyncData and fetch are also executed before the lifecycle hooks. To keep it consistent, this is the case here as well (and makes sense for eg. loading data). Also it's unclear how long that request will take.

What you want is setting the color on the beforeMount hook ☺️
https://codesandbox.io/s/github/manniL/nuxt-4132

But let's wait for more feedback/ideas

Hi @manniL

I have a page with blog posts. Now when I click _next page_ I see:

  • the new posts
  • than the transition (blink)
  • than the new posts again

I store the posts in the store.

So the only workaround for this is to copy the posts reference from the store to new variable in the beforeMount?

It looks ugly :)

Thanks for clarification,

@awronski hi! I also noticed this bug (?). It happens only on dynamic routes, because for some reason in dynamic routes lifecycle order changes from

- beforeRouteLeave 
- middleware
- asyncData
- beforeLeave
- beforeDestroy
- afterLeave
- created

to

- middleware
- asyncData
- beforeRouteUpdate
- beforeLeave
...

So, next route's asyncData is fired before beforeRouteUpdate!!! Crazy, right? I spent a lot of time to figure this out.

@bdrtsky So how do you handle it?

@manniL Could you comment the change of order?

Thanks!

@awronski I decided to force usual flow, by committing a mutations in computed instead of asyncData/fetch while in process.browser

¯_(ツ)_/¯

Thanks for your contribution to Nuxt.js!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of nuxt-edge
  2. Comment the steps to reproduce it

Issues that are labeled as 🕐Pending will not be automatically marked as stale.

@manniL Is this still your preferred way to go around this issue?

@johnRivs nothing changed so far, so yes 😌

@manniL For me this is inconsistent. Why the dynamic routes behave in a different way?
To make it works we have to use workaround like setTimeout or use beforeMount.

It should just work :)

@awronski I agree, but we can't change the behavior for Nuxt 2 as it'd result in breaking changes. We are keeping the problem in mind for Nuxt 3 :relaxed:

Anyone found an elegant way to achieve this? I'm also experiencing this flicker when navigating between nuxt-childern:

API items appear → transition ocurrs → same API items appear.

I just don't know if I'm doing something wrong or not. Also @manniL maybe you know how can I access store in beforeMount()? if at all, I need to call an action. I also need to access the params...

Unfortunately not.

I use this hack:

function commitTimeout (f) {
  if (process.client) {
    setTimeout(() => {
      f()
    }, 100)
  } else {
    f()
  }
}

and then in the store:

   commitTimeout(() => {
      commit('changePostTo', { post, comments })
    })

@awronski - so in fetch() you’re not changing anything, but in your setPosts method you’re calling a delayed version of the commit? How does this help though? From my understanding the items that appear before the transition are there because of fetch()

@awronski - your workaround works well, so thanks for sharing! (I'm putting both methods in store/posts.js). However, I can't understand the logic behind it. Furthermore, even a delay as little as 5ms achieves the desired result for me. What's happening behind the scenes?

@SHxKM I do not retrieve data in the page. I call the store.dispatch in the fetch.

I am not sure why this is working :) I guess that the delay is enough to call beforeRouteUpdate.
Because of the delay the order is the same.

Maybe @manniL can explain it?

I do not retrieve data in the page. I call the store.dispatch in the fetch.

Same here:

async fetch({ params, store, process }) {
        await store.dispatch('posts/getPosts', { page: params.page_num || 1 })
  },

I am not sure why this is working :) I guess that the delay is enough to call beforeRouteUpdate.

This is a real mystery. I see the same order of events happening with or without your workaround. Even 1ms is enough, which means that this isn't simply about the delay per-se.

@SHxKM yes, you see the same order.

But the commit in the store is delayed, so there is time to call beforeRouteUpdate by nuxt.

@awronski - I don’t think 1 millisecond would’ve made that much difference, but what do I know?

Anyway, thanks for sharing your solution.

Even 0ms will do the job. What's happening is similar to Vue's nextTick. By using setTimeout, you're putting things at later time in the stack, in the event loop.

So if what you want to call is X, then comes Y and finally Z, by using setTimeout for X you're putting it after Z. It just happens to be that the final order satisfies our needs for this issue.

This is a pretty horrible hack. How are you supposed to use transition correctly? Seems odd that I have to fire a method to change state to leaving = true so I pre-fade out content before transition does.

Using setTimeout with 0ms does indeed solve the issue. Any update on a cleaner solution for this ?

I am still having this problem. Waiting for other solutions and hopefully next release of NuxtJS could handle this annoying mattter :)

I do not recommend setTimeout anymore.

This hack has serious problem. It can from time to time break your app.
For example the head() method will execute before committing the state.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

surmon-china picture surmon-china  ·  3Comments

uptownhr picture uptownhr  ·  3Comments

mattdharmon picture mattdharmon  ·  3Comments

msudgh picture msudgh  ·  3Comments

shyamchandranmec picture shyamchandranmec  ·  3Comments