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

Server-side rendering #11

Closed
klarstrup opened this issue Oct 28, 2019 · 17 comments
Closed

Server-side rendering #11

klarstrup opened this issue Oct 28, 2019 · 17 comments
Labels

Comments

@klarstrup
Copy link

Any plans to add SSR support?

@Southclaws
Copy link

Southclaws commented Oct 29, 2019

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.

@mattfwood
Copy link
Contributor

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.

@shuding
Copy link
Member

shuding commented Nov 8, 2019

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!

@shuding
Copy link
Member

shuding commented Nov 18, 2019

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 :)

@shuding
Copy link
Member

shuding commented Nov 22, 2019

Closing this issue 🎉

@shuding shuding closed this as completed Nov 22, 2019
@mirshko
Copy link

mirshko commented Jan 8, 2020

@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.

@sergiodxa
Copy link
Contributor

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.

@mirshko
Copy link

mirshko commented Jan 8, 2020

@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.

@possibilities
Copy link

possibilities commented Jan 8, 2020 via email

@sergiodxa
Copy link
Contributor

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.

@mirshko
Copy link

mirshko commented Jan 8, 2020

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.

@cryptiklemur
Copy link
Contributor

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

@sergiodxa
Copy link
Contributor

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.

@mirshko
Copy link

mirshko commented Jan 14, 2020

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

@hems
Copy link

hems commented Apr 27, 2020

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 ( :

@rick-nu
Copy link

rick-nu commented Nov 13, 2020

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

@hems
Copy link

hems commented Nov 13, 2020

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests