-
Notifications
You must be signed in to change notification settings - Fork 35
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
Q: Do we have to create client on every request? #392
Comments
Observations: if I put cache into a constant outside of the function, then cache persists after deployment. If I leave it as is, then cache drops after deployment or if I refresh without cache via browser (shift+cmd+R instead of cmd+R) |
Gonna start this one with a screenshot from the Apollo Client docs on server side rendering: I can't stress this enough: if you are doing SSR, you should never share a client or cache between multiple requests. You will end up mixing private data of multiple users. Apollo Client was not meant to handle the data of multiple users, and even if you use
You use this library. The core point of this library is that requests made on the server during rendering (either made by As for "create a data abstraction layer": Apollo Client is your data abstraction layer here. The same pattern you see with Apollo Client's
Is there any benefit from using a server action here? Why not just make the mutation directly from the browser? You have a client-side cache that you want to update, so involving a third party server seems like a lot of work. Server actions are great if you render all your HTML in a RSC, but the moment you rely on your client-side normalized cache, there isn't a lot of use for them tbh. This circles back to this in our README: Always decide if some data only exists in RSC and the HTML rendered by RSC/Server Actions, or if it's always used by dynamic components based on a cache that lives in the client. Rendering the same data in both of these environments means that something on your screen will end up with stale data. PS: don't worry, on the client you will have one long-existing client, it will not be recreated but accumulate data. |
Sorry my brain broke.. Thanks a lot for helping out! Can you confirm if I got that right? I have a bunch of UI to render a list of items and then each item is editable. So, I render them all in RSC, wrap each item in a form with server action, and stream via suspense.
On the server, we always call the factory function for the sole purpose of dropping the cache on each request so that there's no possibility to mix multiple customers in there.
|
I try to reply inline. I know, this is a lot to take in, and even after two years we're still figuring out best practices ourselves. To preface everything, I want to give you one puzzle piece that might be important, though: On first render, both RSC and Client Components render on the server. This library has three distinct jobs:
As I said, your Client Components already render on the server for the initial page load, so that first render happens on the server, not on the client. I don't think there's a perceivable difference in speed of first render between doing things in RSC or CC.
Keep in mind that for subsequent renders it is probably faster to do things in a Client Component, since then you don't have the back-and-forth between client and server.
I believe you can put
The
You can skip the
Personally I haven't found a lot of good uses for server actions in applications that actually have a lot of dynamic data - and that's the user base we work with most. They are great if you e.g. don't want to have any data-fetching-related JS in the browser bundle and have mostly static data.
You can still do things like making one big query on the page level and then your child components just read from the cache instead of making additional requests.
In the cache, it's one big blob of normalized data with no inidication what the originating query looks like or which headers you sent along with it. So if a query can be resolved from the cache, there's no indiciation if it was actually fetched for this user. You could maybe get around that with very specific schema design, but that would probably not make for a good schema. And even that would be difficult once multiple users are allowed to see the same entitity, but have different access levels, as the same entity will always merge together. |
Makes sense, except 1 thing. You're saying there's no difference if I put items component into RSC or CC because they are both rendered on the server the first time the page is loaded. But I'm using I tested both in RSC devtools. It only works if I navigate from one page to another, not on page refresh. So I went to home and then clicked start recording, then hit the link to the items page.
So, it appears that there is a difference - CC will do CSR and RSC will do SSR. And both will make the request on the server. I think for my usecase CSR is better because after editing 1 item, I may need to sort all items again based on a simple criteria and going to server is a waste. Also the items component is very simple and doesn't use any heavy libs, so no need to over-optimize it. Plus, I don't need to bother with I think I'm good for now, thanks for the help! Feel free to correct me on anything or otherwise close this issue. |
CC will also do SSR on first page load. But it is React's "out of order streaming SSR", so the HTML will be out of order and assembled by JS that is also sent down the wire inline. You can block loading of If you were a search engine, in both cases you wouldn't get spinners but the full rendered HTML in order - the difference is that after that, you also stream down the JS for Client Components and they start hydrating and become interactive. |
The readme here says that for client and for server I have to provide a factory method like
getClient()
ormakeClient()
and call that right before using. In the official docs the client instance is reused.I'm just trying to figure out how to update local cache. The factory methods for both client and server have
new InMemoryCache()
inside, so the cache is reset on every request.use client
and serverimport 'server-only' | 'use server'
files with extension.ts
, so it only deals with data, not UI. I assume with the wrapper, you do reuse the client's client via react context but then why do you ask for a factory method in the readme? And I'm not sure how to update the cache.__typename
andid
would be the same. But right after mutation returns,readQuery
returnsundefined
. Any idea why?My usecase is simple:
The text was updated successfully, but these errors were encountered: