Swr: Server-side rendering

Created on 29 Oct 2019  Â·  17Comments  Â·  Source: vercel/swr

Any plans to add SSR support?

question

Most helpful comment

Hey everyone! With the support of the new initialData option in v0.1.10, you can now use getInitialProps with SWR to do SSR in Next.js without changing too much:

App.getInitialProps = async getInitialProps () {
  const data = await fetcher('/api/data')
  return { data }
}

function App (props) {
  const initialData = props.data
  const { data } = useSWR('/api/data', fetcher, { initialData })

  return <div>{data}</div>
}

In this example, everything works the same just like a normal SSR Next.js app. But it’s also fully powered by SWR in the client side, which means the data can be dynamic and update itself over time / user interactions.

Let us know what you think about this :)

All 17 comments

I think this should be trivial once cache API is exposed, as mentioned in #4 and #16

Finally, we plan to export the cache APIs from the lib, and add options to the config soon. So you can override it with your own implementation like LRU cache, or just manipulate the cache object.

You could replace it with an isomorphic cache.

I imagine the long-term plan for this library is to leverage Suspense + SSR once Suspense is fully released, and I think Next.js will likely do the same. But I agree that in the meantime it would be nice for it to have support in Next.js or other SSR setups to fetch data ahead of time.

Yeah indeed. When we have Suspense supported in server side, we will have this feature out of the box (by just using suspense: true).

But I agree that in the meantime it would be nice for it to have support in Next.js or other SSR setups to fetch data ahead of time.

And yes, we’ve been doing this internally w/ SWR and Next.js for a long time in our dashboard. Will definitely adding the feature to this library. PR soon, stay tuned!

Hey everyone! With the support of the new initialData option in v0.1.10, you can now use getInitialProps with SWR to do SSR in Next.js without changing too much:

App.getInitialProps = async getInitialProps () {
  const data = await fetcher('/api/data')
  return { data }
}

function App (props) {
  const initialData = props.data
  const { data } = useSWR('/api/data', fetcher, { initialData })

  return <div>{data}</div>
}

In this example, everything works the same just like a normal SSR Next.js app. But it’s also fully powered by SWR in the client side, which means the data can be dynamic and update itself over time / user interactions.

Let us know what you think about this :)

Closing this issue 🎉

@quietshu heya!

Seems theres an issue when using isomorphic-unfetch returning an error "Only Absolute URLs are supported" when fetching from getInitialProps.

Any idea about best way around this.

That is not an issue of SWR. It's how sending HTTP requests works server side, you can't use /api/users because the server doesn't know to which host send the request, you need to add localhost:3000 or your production domain.

Maybe you could use env variables to know if you are in development use localhost:3000 and if you are in production use your domain. You should also be able to dynamically get the host using the headers of the request if you want to make it dynamic but not sure how such a good practice is that.

@timneutkens @quietshu any ideas what the best way to grab this host would be?

project is deployed on now. need to be sure the host is properly returned as a now deploy url.

Now provides a header for this:
https://zeit.co/docs/v2/network/headers/#x-now-deployment-url

On Wed, Jan 8, 2020 at 10:34 AM Jeff Reiner notifications@github.com
wrote:

@timneutkens https://github.com/timneutkens @quietshu
https://github.com/quietshu any ideas what the best way to grab this
host would be?

project is deployed on now. need to be sure the host is properly returned
as a now deploy url.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/zeit/swr/issues/11?email_source=notifications&email_token=AAD2X6KLBTFRS3LMPFPALRTQ4XW6XA5CNFSM4JGBSSRKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIM6SUA#issuecomment-572123472,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAD2X6O2L65I6IW3I67TBNDQ4XW6XANCNFSM4JGBSSRA
.

From what I read here https://github.com/zeit/now-builders/issues/55#issuecomment-442968328 you should use the Host headers I mentioned to get actual URL of your app (the deployment URL or the aliased URL) and the x-now-deployment-url header to get the internal deployment URL even if it's aliased.

Only issue here is that you can't use the headers from the ctx of the getInitialProps if you reach the page via client-side routing, not directly.

Not sure best approach to handle that.

You only need the headers if you’re on the server side

You can detect if you are server-side to use the Host in the request and if you are client-side use /api/* directly or access the Host with location.host, maybe you could create a wrapper for that.

function getHost(ctx) {
  if (ctx.req) return ctx.req.headers.host
  return location.host
}

Something like that.

After working this out,

Im noticing some issues where the data is always refetched on page transitions?

It only happens when providing initialData to the useSWR hook.

Im not sure if this is the proper behavior?

But if you dont provide initialData when transitioning pages it always uses the cached data rather than fetching new.

My code for getInitialProps is

Gallery.getInitialProps = async ctx => {
  const data = await fetcher(getHost(ctx) + URL);

  return { initialData: data };
};

and then for the useSWR hook its

const { data } = useSWR(URL, fetcher, {
  initialData
});

URL is simply /api/get-market being a path for the function

App.getInitialProps = async getInitialProps () {
  const data = await fetcher('/api/data')
  return { data }
}

function App (props) {
  const initialData = props.data
  const { data } = useSWR('/api/data', fetcher, { initialData })

  return <div>{data}</div>
}

I believe the issue should be re-open 🤕

One of the greatest things about SWR is that on the second-fetch if the data is in cached it will be served instantly and also "deduping" requests so they don't get fired multiple times in a short period of time.

That's the behaviour I would like to see implemented on the server-side, so if many users hit my homepage at the same time SWR will call the data API only once and render the page extremely fast for everyone ( and then SWR on the client side could kick in ) as opposed for every user having to wait for the same request to be executed on getInitialProps before the initial page load!

For instance:

App.getInitialProps = async getInitialProps () {
  const {data, loading} = useSWR('/api/data', fetcher)
  await loading
  return { data }
}

function App (props) {
  const initialData = props.data
  const { data } = useSWR('/api/data', fetcher, { initialData })

  return <div>{data}</div>
}

Of course, this specific use case could be implemented locally by my application on top of node-cache for instance, so it's not a big deal to don't have it on SWR!

But I think it could be a good addition to SWR ( :

Workaround to cache the server-side initial data on the client side (as long as SWR doens't support it natively): https://www.npmjs.com/package/use-fetch-cache

Workaround to cache the server-side initial data on the client side (as long as SWR doens't support it natively): https://www.npmjs.com/package/use-fetch-cache

that's cool but i feel it should be a feature of useSWR? perhaps you could do a PR / open an issue regarding this?

I believe this issue only discuss the idea of using useSWR on the server-side instead of using a regular fetch method?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tiagocorreiaalmeida picture tiagocorreiaalmeida  Â·  3Comments

Svish picture Svish  Â·  5Comments

bbenezech picture bbenezech  Â·  5Comments

oran1248 picture oran1248  Â·  3Comments

nainardev picture nainardev  Â·  4Comments