-
Notifications
You must be signed in to change notification settings - Fork 36
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
Fetching data on RSC and hydrate the client with that data #124
Comments
The caches in Server Components and in Client Components are completely independent from each other - nothing from the RSC cache will ever be transported to the CC cache. (As for a general rule, Server Components should never display entities that are also displayed in Client Components). You could try to do something like // RSC file
export async function PrefetchQuery({query, variables, children}) {
const { data } = await getClient().query({ query, variables })
return <HydrateQuery query={query} variables={variables} data={data}>{children}</HydrateQuery>
}
// CC file
"use client";
export function HydrateQuery({query, variables, data, children}) {
const hydrated = useRef(false)
const client = useApolloClient()
if (!hydrated.current) {
hydrated.current = true;
client.writeQuery({ query, variables, data })
}
return children
} and then use it like <PrefetchQuery query={ALBUM_COLLECTION_QUERY} variables={initialAlbumListFilters}>
<AlbumCollection/>
</PrefetchQuery> to transport the result over, but to be honest, I haven't experimented around with this too much yet. |
I see your reasoning for creating a separation between RSCs and CCs from a technical perspective. However, thinking about this from the end user, this statement is inherently saying that you can either use Apollo for highly static (RSCs) or dynamic (CCs) cases. However, most apps nowadays sit somewhere in the middle where they are aiming for dynamic at the speed of static experiences. In order to achieve this, you would need to make your RSCs and CCs work together. Using
If you were to rewrite the code above by removing Putting that aside, I was running into the same issue when implementing infinite scrolling. Initially tried a cursed pattern by recursively returning RSCs, but kept running into problems with streaming or nextjs. Ended up implementing a solution similar to the one above. The only caveat, is that not all data is serializable and I need to use
|
@pondorasti our statements do not collide. I said: "Server Components should never display entities that are also displayed in Client Components" As long as you don't display those contents in your server components, but just somehow forward them to the cache of your client components, you are fine. But if you render them out in a server component, and also render them out in a client component, and then the cache changes (as it does, because it is a dynamic normalized cache), your client components would all rerender with the new contents and your server components would stay as they are, because they are static HTML. You want to avoid that at all costs. As for your problem at hand: we've been using the |
Thanks for the detailed explanation and my apologies for the misunderstanding. This makes perfect sense. So what's the story for hydrating CCs from RSCs. Is something like a
Great choice, could even pass those pesky date objects around and still work as expected. Thanks for the tip 🙌🏻 |
I've been thinking about it since we released the library, and I'm not 100% certain on what exactly the API should look like in the end (e.g. a more sophisticated variant might not need to wrap the children) - also it seemed that something on the React/Next.js side might be moving a bit, so I've held back more there, too (it seems like we could use So yeah.. it's on my mind, and it will come eventually, but I'm also very busy with other parts of Apollo Client right now (including trying to get native support for all this into React so we won't need framework-specific wrapper packages anymore), so I can't guarantee for a timeline. |
Awesome, thanks for sharing all these info with me. Looking forward to the changes, and will definitely keep an eye out for the RFC once you've figured out 😉. |
Any updates on this? |
@phryneas // app/posts/page.jsx
import {
dehydrate,
HydrationBoundary,
QueryClient,
} from '@tanstack/react-query'
import Posts from './posts'
export default async function PostsPage() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: getPosts,
})
return (
// Neat! Serialization is now as easy as passing props.
// HydrationBoundary is a Client Component, so hydration will happen there.
<HydrationBoundary state={dehydrate(queryClient)}>
<Posts />
</HydrationBoundary>
)
} and then the // app/posts/posts.jsx
'use client'
export default function Posts() {
// This useQuery could just as well happen in some deeper
// child to <Posts>, data will be available immediately either way
const { data } = useQuery({ queryKey: ['posts'], queryFn: getPosts })
// This query was not prefetched on the server and will not start
// fetching until on the client, both patterns are fine to mix.
const { data: commentsData } = useQuery({
queryKey: ['posts-comments'],
queryFn: getComments,
})
// ...
} |
did you succeed? |
Hey all 👋 Support for preloading in RSC and using that data to populate the cache in client components was released in 0.11.0. If I'm reading the issue right, I believe this is what you're looking for! |
Yup, as Jerel said, this has been released - please try it out. |
Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better. |
Hello,
I'm building a page that displays music albums, has an infinite loader and also a bunch of filtering options. I'm using Next.js v13.5.4 with the app dir, and Contentful to retrieve my data. In order to setup Apollo, I followed the guidelines reported here.
What I'd like to do is:
fetchMore
orrefetch
are called (for the infinite loader and the filters).At the moment I'm handling the process like this:
My idea was that if I made the query on the RSC first, the client would have populated itself without making the query another time, but that's not happening and I don't think I understood how this should properly work. Since there are not many topics about it around, could you help me understand the correct workflow to follow for these use cases?
Thank you
The text was updated successfully, but these errors were encountered: