Hello,
I am currently working on a Next.js application using Apollo Client, specifically utilizing renderToStringWithData
for server-side rendering (SSR). I have come across a peculiar issue: when the application is accessed from multiple browser tabs simultaneously, one of the tabs seems to render the page without waiting for the data fetching request to fully complete.
This behavior is inconsistent, as it only happens during simultaneous requests, suggesting a potential race condition or a performance issue under high concurrency/load. The expected behavior is that all pages, regardless of how they are accessed, wait for the data fetching to complete before being rendered, ensuring data consistency and a reliable user experience.
Here are some specifics of my setup:
- Next.js version: [12.2.2]
- Apollo Client version: [3.6.8]
- Warn messages : [Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.]
My code
- _document.tsx
class MyDocument extends Document<CustomDocumentProps> {
constructor(props: CustomDocumentProps) {
super(props);
const { __NEXT_DATA__, apolloState } = props;
__NEXT_DATA__.apolloState = apolloState;
}
static async getInitialProps(ctx: DocumentContext) {
await renderToStringWithData(<ctx.AppTree pageProps={{}} />);
const initialProps = await Document.getInitialProps(ctx);
const client = initializeApollo(undefined);
const apolloState = client.extract();
await client.clearStore();
return {
...initialProps,
apolloState,
};
}
-_app.tsx
function MyApp({ Component, pageProps }: AppPageProps) {
const client = useApollo();
return (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
);
}
- apollo-cache.ts
export const APOLLO_STATE_PROP_NAME = "__APOLLO_STATE__";
let apolloClient: ApolloClient<NormalizedCacheObject> | null;
const createApolloClient = () => {
return new ApolloClient({
ssrMode:true,
cache,
...
});
};
export const initializeApollo = (initialState?: unknown) => {
const _apolloClient = apolloClient ?? createApolloClient();
if (initialState) {
const existingCache = _apolloClient.cache.extract();
// @ts-ignore
const data = deepMerge(initialState, existingCache, {
arrayMerge: (destinationArray, sourceArray) => [
...sourceArray,
...destinationArray.filter((d) => sourceArray.every((s) => !isEqual(d, s))),
],
});
_apolloClient.cache.restore(data);
}
if (typeof window === "undefined") return _apolloClient;
if (!apolloClient) {
apolloClient = _apolloClient;
}
return _apolloClient;
};
export const useApollo = () => {
// @ts-ignore
const state = typeof window !== "undefined" ? window.__NEXT_DATA__.apolloState : undefined;
const client = useMemo(() => {
return initializeApollo(state);
}, [state]);
return client;
};
I am trying to understand the underlying cause of this issue and am looking for guidance on how to ensure that rendering only occurs after all requests have successfully completed, even when multiple tabs are opened and accessed simultaneously. Any insights, suggestions, or recommendations would be greatly appreciated.
Thank you in advance for your assistance.