Next.js: How to combine getServerSideProps and useSWR (server side props as initial value)

May 24, 2020

Next's SSR feature is very useful for SEO. But sometimes you may want to have the server fetch the initial state and allow the client side to later fetch some other data and update the sate.

For example, in my project daily-trend, I render the search results with default parameters on the server side, but I also want to allow users to search with different parameters. This means the client should be able to overwrite the props passed by the server later on.

Let's first ignore the server side rendering. If we just want to fetch data on the client side, it's quite easy to achieve. You can just use useSwr, which works like a combination of useEffect and useState.

For example:

const fetcher = url => axios.get(url).then(res => res.data)
const {data, error} = useSwr('api/user', fetcher)

This is similar to creating a state with useState and then fetching data from a server and setting its value in useEffect. However useSwr is in most cases better in that it handles caching and uses cached data before it gets a response, making the webpage feel more smooth and fluid.

And if your key changes as a result of the user interacting with the app, useSwr will refetch the data to make sure the data is up to date.

For example, my key mey be api/user${someState}. If someState changed, obvious the key will change, causing a re-render.

That all sounds pretty good. But what if I want to use SSR? Going back to the daily-trend example, I want to assign data an initial value from the server while keeping the search functionality. How do I do it?

The good news is, useSwr has an initialData option that allows you to give it an initial value as an option in its 3rd parameter. So you can fetch data in getServerSideProps and pass it to the page component as a prop.

const {data, error} = useSwr(key, fetcher, {
    initialData: props.dataFromServerSideProps
})

But here's the catch: initialData works on a per swr basis, meaning even if the user changes the key, it will still return the initial value without refetching the data. So even if I change the parameters and hit search, I will still see the same data.

To resolve this problem, one work around I found is to create the key you feed to useSwr as a state and use useSwr as follows:

const {data, error} = useSwr(key, fetcher, {
    initialData: key === props.initialKey ? {props.dataFromServerSideProps} : null
})

This way, if the use changes the key, useSwr won't receive the props from the server, so useSwr will fetch data properly without returning the initial data.

Full code: https://github.com/imjamesku/trending-topics/blob/master/pages/index.tsx

Subscribe to my email list

© 2024 ALL RIGHTS RESERVED