vercel / swr

React Hooks for Data Fetching
https://swr.vercel.app
MIT License
30.43k stars 1.22k forks source link

Data is not updated with `initialData` #284

Closed Kerumen closed 3 years ago

Kerumen commented 4 years ago

I'm on a Next.js app and here is my (simplified) code:

const IndexPage = ({ data: initialData }) => {
  const [filters, setFilters] = useState(defaultFilters)

  const onChange = () => {
    ...
    setFilters(newFilters)
  }

  const query = getQuery(filters)
  const { data } = useSWR(`/api/resorts?${query}`, fetcher, { initialData })

  return (...)
}

Index.getInitialProps = async ctx => {
  const query = getQuery(defaultFilters)
  const data: Resort[] = await fetcher(`${getHost(ctx)}/api/resorts?${query}`)
  return { data }
}

I have an initial set of filter (defaultFilters) on which I query and pass to useSWR with initialData on first render. When the user changes one filter, the key should change as it's a new query, but useSWR still returns the old data, from the first call.

When I remove initialData from useSWR it works but that's not what I want, I want to have SSR.

Am I doing something wrong?

shuding commented 3 years ago

As #284 (comment) mentioned, the new Cache API will be the official replacement of initialData for many use cases. Please try it out! We have a more detailed docs here too: swr.vercel.app/advanced/cache.

How is this exactly supposed to work? What is the canonical way of solving this problem?

There's a full example here: #284 (comment), and we will also update the docs soon.

patroza commented 3 years ago

As #284 (comment) mentioned, the new Cache API will be the official replacement of initialData for many use cases. Please try it out! We have a more detailed docs here too: swr.vercel.app/advanced/cache.

How is this exactly supposed to work? What is the canonical way of solving this problem?

There's a full example here: #284 (comment), and we will also update the docs soon.

alright, but how does that address that the cached value needs to be replaced by the server side rendered data that is fetched by NextJS when you navigate to the page again? Repro:

  1. Visit page
  2. Visit another page
  3. Visit first page again, the freshly fetched SSR data is not applied because there is (stale) cache data already.

So doesn't the problem remain the same? Or am I overlooking something obvious?

Basically, what is required is that the Cache is ignored on mount when SSR data is in play.

Second, I think an example which stores a cache store as a global variable inside a page file is perhaps not a good example, especially considering SSR, memory leak potential and accidental data sharing :)

shuding commented 3 years ago

If it’s specifically SSR/SSG, the initial props comes to the very top level page component, we can initial the cache inside a ref or a state. So when that page gets remounted the cache will be reinitialized again, works just like a context provider. Does that work for you?

// initial props from SSR/SSG
function Page(props) {
  // using state to lazily init it
  const [cache] = useState(() => createCache(new Map(props)))
  return <SWRConfig value={{cache}}>
    <App/>
  </SWRConfig>
}

With this approach the cache will be strictly scoped to the page. Of course we can do some global cache fallback inside that Map (so we can also have app-level cache), will get an example too if necessary.

huozhi commented 3 years ago

We released SWR 1.0 with better preloaded cache solution. Checkout cache doc for details.

For fallback purpose, initialData is renamed to fallbackData if you don't need any preloaded state in cache.

1ambda commented 3 years ago

Hi, have a question.

If cache is now available per page, what's the difference between fallbackData and page-scoped cache while data is generated and passed from getServersideProps?

Thanks.

VladimirMikulic commented 2 years ago

@huozhi I have this issue as well with fallbackData and revalidateOnMount set to false. The code is the same as the one @Kerumen posted when opening this issue.

The key changes, but SWR never actually makes that call which results in fallbackData always being the value of data returned by swr.

It's like #1422 but in my case, it's data is never fetched/revalidated on key change if fallbackData and revalidateOnMount: false are specified.

huozhi commented 2 years ago

@VladimirMikulic Can you file a new issue if you have problems with it?