This package provides integrations between Apollo Client and React Router 7 to support modern streaming SSR.
Install dependencies:
npm i @apollo/client-integration-react-router @apollo/client graphql
Create an app/apollo.ts
with that exports a makeClient
function and an apolloLoader
created with createApolloLoaderHandler
:
import { ApolloLink, HttpLink, InMemoryCache } from "@apollo/client/index.js";
import {
createApolloLoaderHandler,
ApolloClient,
} from "@apollo/client-integration-react-router";
// `request` will be available on the server during SSR or in loaders, but not in the browser
export const makeClient = (request?: Request) => {
return new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({ uri: "https://your.graphql.api" }),
});
};
export const apolloLoader = createApolloLoaderHandler(makeClient);
[!IMPORTANT]
ApolloClient
needs to be imported from@apollo/client-integration-react-router
, not from@apollo/client
.
Run yarn react-router reveal
. This will create the files app/entry.client.tsx
and app/entry.server.tsx
.
Adjust app/entry.client.tsx
:
+import { makeClient } from "./apollo";
+import { ApolloProvider } from "@apollo/client/index.js";
startTransition(() => {
+ const client = makeClient();
hydrateRoot(
document,
<StrictMode>
+ <ApolloProvider client={client}>
<HydratedRouter />
+ </ApolloProvider>
</StrictMode>
);
});
Adjust app/entry.server.tsx
:
+import { makeClient } from "./apollo";
+import { ApolloProvider } from "@apollo/client/index.js";
export default function handleRequest(
// ...
) {
return new Promise((resolve, reject) => {
// ...
+ const client = makeClient(request);
const { pipe, abort } = renderToPipeableStream(
+ <ApolloProvider client={client}>
<ServerRouter
context={routerContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
+ </ApolloProvider>,
{
[readyOption]() {
shellRendered = true;
Add <ApolloHydrationHelper>
to app/root.tsx
+ import { ApolloHydrationHelper } from "@apollo/client-integration-react-router";
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
// ...
<body>
- {children}
+ <ApolloHydrationHelper>{children}</ApolloHydrationHelper>
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
You can now use the apolloLoader
function to create Apollo-enabled loaders:
export const loader = apolloLoader<Route.LoaderArgs>()(({ preloadQuery }) => {
const myQueryRef = preloadQuery(MY_QUERY, {
variables: { someVariable: 1 },
});
return {
myQueryRef,
};
});
[!IMPORTANT]
To provide you with better TypeScript support, this is a method that you need to call twice:apolloLoader<LoaderArgs>()(loader)
Then you can consume this myQueryRef
object with useReadQuery
in your component:
export default function Home() {
const { myQueryRef } = useLoaderData<typeof loader>();
const { data } = useReadQuery(myQueryRef);
return (
<div> do something with `data` here </div>
)