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

feat(vue-app): new fetch #5118

Closed
wants to merge 24 commits into from
Closed

feat(vue-app): new fetch #5118

wants to merge 24 commits into from

Conversation

atinux
Copy link
Member

@atinux atinux commented Feb 26, 2019

RFC

Please carefully read our RFC for it: nuxt/rfcs#27

Description

To see an example in action, please take a look at the examples/v3/fetch/ with a detailed explanation.

This PR will allow to use fetch in every Vue components with access to this inside the method. I've been waiting since the creation of Nuxt.js to have this feature, and I am really happy that we worked on a workaround with the core team (thanks Evan & Guillaume Chau) and now shipped with Vue 2.6: serverPrefetch.

serverPrefetch is great for the SSR part. The complicated part is when navigating on client-side since Nuxt 1 & 2 wait for the asyncData/fetch calls to be done before rendering the next route (by using router.beforeEach).

It introduces at the component level:

  • fetch hook in the page/component to be used while asyncData is called, it should be a string for a global component or directly a component object
  • this.$isFetching in the component to display a placeholder while fetch is being called (on client-side or when fetchOnServer is false when rendering the component on the server).
  • fetchOnServer (default to true) to call or not fetch hook when server rendering the component
  • this.$fetch() in the component to re-call fetch hook ($isFetching will become true again)
  • this._lastFetchAt (exists if fetch hook is present): timestamp of the last fetch call made (ssr included), useful for caching combined with keep-alive on <nuxt> and <nuxt-child> components
  • this._hydrated to know if this component has been hydrated and fetch has not been called on client-side.

It also introduces at the app level:

  • this.$nuxt.state (before: nuxtState given in beforeNuxtRender) that you can overwrite and will be rendered as window.__NUXT__. The value is also setup on client side to hydrate your plugins.
  • this.$nuxt.isFetching to know if any component is actually calling fetch (useful for a global loading page)
  • this.$nuxt.nbFetchin to know how many fetch are pending

It removes:

  • asyncData: Since you can mutate the components data right inside fetch, you don't need to have asyncData anymore. Also, Nuxt smartly detects what properties has been mutated in order to returned the minimum JSON with the HTML.

What about waiting fetch calls before navigating to the next page?

I found a way to wait before rendering the next route (like actual Nuxt UX), but it was too tricky:
Using <transition> listeners beforeEnter + enter and leave to wait before transitioning the component while initializing the virtual DOM and calling fetch.
-> keep-alive and page transitions were broken (since I was hacking ).

I also tried to overwrite the render method of the component by giving a component to a placeholder property. I also worked on a <placeholder> block next to the <template> block (I worked with @znck on it).
-> It looked more messy that simply deal with $isFetching and it did not fix the way to "wait" for the components to be fetched before showing the next route.

Some people may say that it's the same UX of React Suspense, I did not know, I had this feature in mind since a long time (I was calling it "Reactive Loading" 😄).

Resolves #3776, #32 and #127

TODO:

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly. (PR: #)
  • I have added tests to cover my changes (if not applicable, please state why)
  • All new and existing tests are passing.

@galvez
Copy link

galvez commented Feb 26, 2019

giphy

@jagreehal
Copy link

Just so I understand correctly does this resolve #32?

@manniL
Copy link
Member

manniL commented Feb 26, 2019

@jagreehal Yes.

@atinux atinux changed the title feat(vue-app): asyncData/fetch everywhere feat(vue-app): Nuxt 3 fetch Mar 11, 2019
@lilianaziolek
Copy link

lilianaziolek commented Mar 12, 2019

@atinux These changes in fetch seem great, I always missed the ability to put fetch of stuff in components not just pages.
One perhaps related question is how fetch is supposed to work in regards to route params (i.e. products/_category) - mind, I don't mind route query (products?category=XXX). It seems to me that there is currently no way to make fetch be called on route params changes (it can be done on route query changes with the extra flag). I've been using watch $route for this purpose but it feels like fetch should react to changes in params too, as they are actually very likely to require data changes in the component/page. Otherwise I end up with some weird workarounds to avoid duplicating code between fetch and watch.
Can you please

  1. Confirm that this is the case and I'm not missing something, and it is correct that fetch cannot react on params changes right now (if not correct - what have I missed?)
  2. Was there any reason for this design decision? Will this reason still stand with the changes described above, or perhaps this could be improved as well?

UPDATE: I just managed to find more details about one of your examples and seems like fetch does indeed react to params change (with the post id) - which is great news! So just to double check - is this functionality also new? Or can this be achieved in Nuxt 2 as well ?

@atinux
Copy link
Member Author

atinux commented Mar 12, 2019

Hi @lilianaziolek

Actually, when a component is re-used and a route params change, Vue will call beforeMount hook that will automatically call fetch 😄
-> YES, fetch will react to params changes

Also, for sub components, you can directly watch for $route or directly give props to the components, example: <Post :post-id="$route.params.id" />

@henriqemalheiros
Copy link

henriqemalheiros commented Mar 13, 2019

So there are no plans to support await fetch before route change?

@hartmut-co-uk there is this example of asyncData being supported via a separate Nuxt module. I have some projects where it would be better to keep the current behaviour, so this looks promising.

@atinux I like @hartmut-co-uk's idea of waiting for the "route specific" API response. Maybe we could await fetch only on page components? Maybe even put it behind a flag, like loading, set as false by default.

@atinux
Copy link
Member Author

atinux commented Mar 14, 2019

Thank you for your feedbacks @hartmut-co-uk and @henriqemalheiros

I just created an RFC for it so we can discuss about this situation: nuxt/rfcs#27

@tsongas
Copy link

tsongas commented Mar 19, 2019

I'm just starting to learn Nuxt so I have feedback from that perspective. I'm stoked on Vue for bringing more simplicity and fun to front end development. I was stoked on Nuxt for similar reasons, until I got to Vuex which is when it became less fun. I think React developers are figuring out Redux was an important step in the development of state management, but want less boilerplate and are moving to alternatives like MobX-State-Tree. So, I would hate to see Nuxt continue to follow what has turned out to be not such a developer friendly solution to state management in Redux/Vuex if there are better alternatives. See https://hackernoon.com/the-react-state-museum-a278c726315 for a rundown. To me the most exciting is https://github.com/jamiebuilds/unstated, I wonder if it could help inspire a way to simplify state management and fetching data with Nuxt, especially universal which gets confusing.

@atinux
Copy link
Member Author

atinux commented Mar 21, 2019

Thank you for your feedback @tsongas

Simplicity is part of Nuxt vision, this is why we have the store/ directory that simplify Vuex usage (see https://nuxtjs.org/guide/vuex-store).

Actually, fetch is not related to Vuex and works without it.
The next step is indeed to simplify the way of calling asynchronous data while being as simple (and powerful) as possible :)

@husayt
Copy link
Contributor

husayt commented Mar 22, 2019

@tsongas it might be slightly bumpy to get to understand vuex at first, but it is not even closely as complex as Redux. In fact, with Vuex they managed to simplify what normally is a very complex concept - State management. Nuxt takes it to next level by providing it hassle and setup free.

What I could suggest is to use it with vuex-class (via nuxt-property-decorator or directly).

Rather than moving away from Vuex, which has become a standard in Vue community, we should seek to make it richer and simpler to use. I am really looking forward to Vuex 4 and wish it could be prioritised, as it covers many of your concerns:

Here is some of the coming features from Vue.js roadmap

Vuex 4.x

  • Simplify usage
    • Getting rid of mapXXX helpers via scoped-slot based store consumer component
    • Getting rid of the need for separating actions and mutations
  • Better TypeScript inference (may require API redesign)
  • Accompanying DevTools update
  • Actionable: kickoff public design thread

@pi0 pi0 added the draft label Apr 20, 2019
@pi0 pi0 changed the title feat(vue-app): Nuxt 3 fetch feat(vue-app): new fetch Apr 20, 2019
@pi0 pi0 added the 3.x label Apr 20, 2019
@MLDMoritz
Copy link

This would allow keep-alive to not wait for the asyncData but loading it 'on-the-fly' - am I right? So getting back to the page before won't trigger fetch?

@stale stale bot added the stale label Jun 7, 2019
@manniL manniL removed the stale label Jun 7, 2019
@pi0 pi0 changed the base branch from dev to next June 14, 2019 17:56
@nuxt nuxt deleted a comment from stale bot Jun 14, 2019
@stale
Copy link

stale bot commented Jul 5, 2019

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.

@stale stale bot added the stale label Jul 5, 2019
@stale stale bot closed this Jul 12, 2019
@atinux atinux reopened this Jul 12, 2019
@stale stale bot removed the stale label Jul 12, 2019
@stale
Copy link

stale bot commented Aug 2, 2019

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.

@stale stale bot added the stale label Aug 2, 2019
@atinux atinux added pending and removed stale labels Aug 7, 2019
@atinux atinux mentioned this pull request Jan 16, 2020
7 tasks
@atinux
Copy link
Member Author

atinux commented Jan 16, 2020

I am closing this PR in favour of #6880 since it does not remove the actual behaviour 😄

@atinux atinux closed this Jan 16, 2020
@pi0 pi0 deleted the feat/async-data branch July 2, 2020 10:33
@danielroe danielroe added the 2.x label Jan 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.