nuxt-community / composition-api

Composition API hooks for Nuxt 2.
https://composition-api.nuxtjs.org
MIT License
709 stars 101 forks source link

docs: explain useAsync 'refresh' strategy #171

Open crutch12 opened 4 years ago

crutch12 commented 4 years ago

🐛 The bug When use useAsync method in setup function, it puts loaded data in window.nuxt.ssrRefs

https://github.com/nuxt-community/composition-api/blob/77e289134e9ed2b7d7f0efa165f6a23a5c8b1982/src/ssr-ref.ts#L21

And when you go to another page (with vue router) and return back - nuxt doesn't send request again, because you still have preloaded data in window.nuxt.ssrRefs

🛠️ To reproduce With SSR (universal) mode:

  1. Use useAsyncin setup function, write some request here or add debugger
  2. After page loaded (requests completed) go to another page (with nuxt-link)
  3. Return back (browser's back button)
  4. You will see, that first opened in SSR page on returning doesn't execute code inside useAsync again. But it has to!

When you go to another pages everything works fine, because there is no hydration step in browser's useAsync implementation.

I'd be very grateful for a link to a gist or repo that reproduces the bug. // @TODO

🌈 Expected behaviour I think window.nuxt.ssrRefs has to be cleared after hydration. Or maybe we could add some flag for this behaviour in useAsync function.

ℹ️ Additional context Also this line of code looks really strange :) https://github.com/nuxt-community/composition-api/blob/77e289134e9ed2b7d7f0efa165f6a23a5c8b1982/src/ssr-ref.ts#L20

danielroe commented 4 years ago

This is intentional behaviour. Could you explain your use case for rerunning the async function on navigation?

crutch12 commented 4 years ago

Hi

1) It doesn't look like intentional behaviour because it works this way only with first loaded page. Another pages always rerun the async function on navigation

2) My use case is data change (dynamic data). If my data is collection of items, it could be changed while navigation to other pages, so I would like to refetch this data when came back on first loaded page.

danielroe commented 4 years ago

Would you have the same feeling about ssrRefs more generally, or just with useAsync?

crutch12 commented 4 years ago

@danielroe I use useAsync function, not ssrRefs methods :) I would like to useAsync could work same as nuxt's asyncData and I could reload data returning on page through navigation.

mahapo commented 4 years ago

@crutch12 I had a similar issue. The useAsync wasn't triggered on route change. I fix it by adding the path to the key argument. Maybe this fix your issue.

  const { $storyblok, route } = useContext()
  const story = useAsync(() => $storyblok.getCurrentStory(), route.value.path)
mathe42 commented 4 years ago

When I wrote this code (useAsync) I wantet that it works like in @mahapo workaround. I created a PR to fix this.

aaronhuisinga commented 4 years ago

This definitely has confused our team as well. We expected this to function similarly to asyncData and have been having all sorts of issues with navigating via nuxt-link to a page with dynamic data and having the page populated with stale data from before.

For all dynamic pages in our application, we need the guarantee that our useAsync method is run when the page is loaded, whether via SSR or via a link click. I currently don't see a way to do this within the Nuxt Composition API.

mathe42 commented 4 years ago

@aaronhuisinga See https://github.com/nuxt-community/composition-api/pull/223

cmorbitzer commented 3 years ago

Just to be clear, #223 did not fix this issue. To reproduce:

  1. Navigate to a page, which has a useAsync hook inside the setup function
  2. Navigate away from that page using nuxt-link
  3. Return to the original page also using nuxt-link

I expect the useAsync callback to run again, like asyncData, but it does not. This is problematic if the first page fetches data that it needs to render, and the second page changes that data, because when returning to the first page, the data rendered is stale instead of being fetched again from the server

mathe42 commented 3 years ago

That is intended and not a bug! - Yes the naming is bad but you can provide a route specific key.

aaronhuisinga commented 3 years ago

@mathe42 @danielroe The big issue here is with web applications that have data that can change.

For example, if we have a blog:

  1. We navigate to /posts/1234/edit. The details of the post are loaded into the edit form via SSR.
  2. We make changes to the post title and content, and save the post. It's updated in the database. We are redirected away from the edit form back to the posts index page.
  3. We navigate back to /posts/1234/edit. The form is automatically populated with the old data that was originally fetched server side.

Even with keying our calls using the route, we're unable to get around this issue. The only thing we've found that works to prevent this is setting window.__NUXT__.ssrRefs['/posts/1234/edit'] = null thus forcing a re-fetch when the user navigates back to the page. This implementation makes using SSR for dynamic web applications challenging, as users are often presented with out of date data and are forced to refresh.

Is there something that we're missing with this implementation, or is this currently just a limitation of the available Composition API methods? While using the options API and asyncData, I don't believe this was ever an issue for us.

mathe42 commented 3 years ago

Than use useFetch. Or implement your own! Have a look what onServerPrefetch does and you can implement it in notime.

I use useAsync on a webpage where the data is in most cases static. And I think it is great - if you fetched the data before and you navigate back no loading! As you would expect.

Maybe the following pattern would be a good idea for you:

function getData() {
  return fetch('url') //... do stuff return promise
}

const data = useAsync(() => {
  return getData()
})

function refreshData() {
  getData.then(d=>data.value=d)
}
aaronhuisinga commented 3 years ago

@mathe42 useFetch does indeed appear to fix the issues we have been having with this. It would be great if the documentation were a little more verbose about covering the different use cases. In hindsight and after reading through the source it all makes sense, but for us the documentation in this case didn't seem to touch on a lot of this.

Thanks for your help!