apollographql / apollographql/apollo-client-integrations
Pagination & Caching with Server-Preloaded Client Components
- Dominant language
- TypeScript
- Stars
- 556
- Forks
- 53
- PR merge metrics
- No merged PRs in 30d
Description
In Next.js I'm using a Server Component to preload data into a Client Component using `preloadQuery` and `useSuspenseQuery`. If javascript is enabled, the Client Component uses `fetchMore` + `offsetLimitPagination()` to do an infinite scroll. This all works fine.
When javascript is disabled, a classic link-based pagination is displayed which uses a `page` url query to display each page of results. The `page` query string value is passed to the component and used to set the `offset` variable before the query is executed.
Server component:
```
export default function RecipeEntriesList({ pageNum }: { pageNum: number }) {
// query variables are initialized in the
// Server Component then passed to the Client Component
const queryLimit = 10;
const queryVariables: QueryVariables = {
section: ["recipes"],
limit: queryLimit,
offset: (pageNum - 1) * queryLimit, // 0 if on the first page
};
return (
);
}
```
Client component:
```
export default function RecipeEntriesListClient({
queryVariables,
}: {
queryVariables: QueryVariables;
}) {
// offset is mutable in the client component
// so we copy the initial value into a ref
const queryOffset = useRef(queryVariables.offset);
const { data, error, networkStatus, fetchMore } =
useSuspenseQuery(GET_RECIPE_ENTRIES, {
variables: queryVariables, // defined in the Recipe Entries server component
});
const inViewRef = useOnInView((inView) => {
if (inView && data && data.recipeList.length < data.entryCount) {
fetchMore({
variables: {
offset: (queryOffset.current = data.recipeList.length),
},
});
}
});
// ...
```
This does not work as expected. The entries from page 1 are displayed no matter which page query string is being accessed. I assume this has to do with how Apollo is caching the entries, but I don't know what I'm doing wrong. I have a separate `InMemoryCache` for the server component that lists `offset` as a keyArg but it doesn't seem to have an effect:
```
const keyArgs = ["section", "offset"];
const queryCache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
entries: {
keyArgs: keyArgs
},
entryCount: {
keyArgs: keyArgs,
},
},
},
},
});
```
I'm surprised this is happening since the server cache gets thrown out immediately anyway so I don't really understand what's wrong. Here's a [CodeSandbox with the full setup](https://codesandbox.io/p/devbox/apollo-client-rsc-pagination-demo-ymqqwl).
Contributor guide
No contributing guide indexed for this repository
Research direction
Reproduce the linked CodeSandbox and start with RecipeEntriesList, RecipeEntriesListClient, and the separate InMemoryCache typePolicies. Trace how the page-derived offset reaches preloadQuery and useSuspenseQuery, then verify that each page shows its requested entries while client-side fetchMore and infinite scroll still work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100