Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non blocking navigation #41

Open
pi0 opened this issue Feb 4, 2021 · 9 comments
Open

Non blocking navigation #41

pi0 opened this issue Feb 4, 2021 · 9 comments
Assignees

Comments

@pi0
Copy link
Member

pi0 commented Feb 4, 2021

One of newer features nuxt introduced in v2.12 (it is before original nuxt-movies project created i guess) is fetch hook which in comparation to asyncData, awaits during server-side-rendering but does not blocks route change with client-side navigation. This gives us possibility to quickly navigate to next page while individual parts of page are loading. Which can be by a skeleton but we usually have some vital meta from current page in global state like movie title so can reuse it. (this technique is used in nuxt hackernews demo for example)

Action points:

  • Try method for landing to movie navigation
  • Investigate limitations that it brings that developers may want to avoid
  • Compare user experience and possible introduced layout shifts
@anton-karlovskiy
Copy link
Member

anton-karlovskiy commented Feb 5, 2021

@pi0 I was going to suggest using fetch.
I thought that we would have to use keep-alive directive and activated hook together.
Is it OK for me to take this task and update the project?
cc @addyosmani

@anton-karlovskiy
Copy link
Member

anton-karlovskiy commented Feb 5, 2021

@addyosmani @pi0 @danielroe
Do you think it's worth adding keep-alive and activated together with fetch?
One thing I'd like to know is how we can measure the performance before/after using keep-alive and activated as they are related to caching. I guess Lighthouse clears all cached data before starting to audit.

@pi0
Copy link
Member Author

pi0 commented Feb 5, 2021

Hi @anton-karlovskiy. Actually it is nice to also use keep-alive to reuse created dom elements and vue instance. Also it is important to keep reusable data in global state (vuex store or state plugin) this way we can use it across pages and possibly keep only data in memory rather than dom.

@anton-karlovskiy
Copy link
Member

Hi @pi0
Yes, I understood your points.
Thank you for your advice. I'll update the PR in that way. :)

@addyosmani
Copy link
Member

Is it OK for me to take this task and update the project?
SGTM!

@anton-karlovskiy
Copy link
Member

anton-karlovskiy commented Feb 10, 2021

Hi @pi0

Also it is important to keep reusable data in global state (vuex store or state plugin) this way we can use it across pages and possibly keep only data in memory rather than dom. (#41 (comment))

Tip: For data-reuse technique, we need a global store object otherwise fetched data will be lost (refetched) when going to a page and coming back. (#44 (comment))

I'd like to ask a few questions.
As long as we use keep-alive, I'm wondering if the fetched data won't be lost (refetched) according to:

Nuxt allows caching a certain number of pages in the memory along with their fetched data. (https://nuxtjs.org/blog/understanding-how-fetch-works-in-nuxt-2-12/#making-nuxt-pages-more-performant)

Actually, at the beginning of the project, we dropped Vuex as it's optional and has overhead. (#3 (comment))
So I think I have not understood why we need a global state.

Please correct me if I'm wrong. Thank you.

cc @danielroe @addyosmani

@anton-karlovskiy
Copy link
Member

anton-karlovskiy commented Feb 10, 2021

@pi0 @danielroe @addyosmani

Compare user experience and possible introduced layout shifts

After replacing asyncData with fetch, I think the user experience has regressed, especially the CLS has increased.
Please try this URL: https://nuxt-movies-h0zk6tina.vercel.app/.
It might be required to implement some skeleton UI or at least loading spinner for improving the user experience.

After adopting keep-alive, because of the cached data, it might be difficult to notice the CLS.
Here is the URL: https://nuxt-movies-27v5tfja1.vercel.app/

@anton-karlovskiy
Copy link
Member

anton-karlovskiy commented Feb 11, 2021

@pi0 @danielroe
I've checked the hackernews project and I'd like to ask some questions.

As far as I know, the main reason we need a global state like vuex there is to apply cache logic:

  • For example, once we land on a page, we fetch the relevant data from the server and put it in the store.
  • If we re-visit that page, we look into the store and if the data is available, we use that data instead of fetching again from the server.
  • Considering the stale data case, we set a timeout threshold to determine whether to fetch the data from the server or to use the data in the store.

If I'm correct, I'd like to continue :)
In my opinion, in React ecosystem, for such a purpose, I think we can use react-query, swr, apollo-client.
Those packages help us decouple cache mechanism from state management.
Just from my experience in React development, I felt difficult to use Redux for implementing cache logic as well as state management.

In Vue.js/Nuxt.js development, could we use a similar approach to using SWR with Next.js? For example: https://github.com/Kong/swrv

@addyosmani I'd suggest using Vuex only if that suits the app needs (truly global, app-wide state). The Nuxt integration is pretty seamless, but I feel best practice is moving more to letting components manage their own state with swr/swrv-style data flow.

from @danielroe's notes at #3 (comment)

Please correct me if I'm wrong :) Thank you.
cc @addyosmani

@pi0
Copy link
Member Author

pi0 commented Feb 16, 2021

Hi @anton-karlovskiy. I fully agree that using swr fetching for cache would be much better to cache API responses rather than keeping them in global state (vuex or other solution).

But consider that we can use a cached response if it was fetched once before. When a new users comes to page A and navigates to B, she/he doesn't have payload for B (even if client side swr cache implemented). So with a non-blocking navigation when goes to page B, should wait for B's payload to be fetched in order to see rendered content while we can smartly reuse part of A's payload (like we already know movie title by it's id and can also start fetching poster image in parallel to payload fetching). This is possible with graphql resolver caching or custom logic for REST apis. In either way this is an optional performance improvement to show meaningful content to user as soon as possible when doing client-side navigation :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants