Configuring relay-nextjs
Installing relay-nextjs
Install using npm or your other favorite package manager:
npm install relay-nextjs
Routing Integration
relay-nextjs
must be configured in a custom _app
to properly intercept and
handle routing.
Setting up the Relay Environment
For basic information about the Relay environment please see the Relay docs.
relay-nextjs
was designed with both client-side and server-side rendering in
mind. As such it needs to be able to use either a client-side or server-side
Relay environment. The library knows how to handle which environment to use, but
we have to tell it how to create these environments. For this we will define two
functions: getClientEnvironment
and createServerEnvironment
. Note the
distinction — on the client only one environment is ever created because there
is only one app, but on the server we must create an environment per-render to
ensure the cache is not shared between requests.
First let’s define getClientEnvironment
:
// lib/client_environment.ts
import { Environment, Network, Store, RecordSource } from 'relay-runtime';
export function createClientNetwork() {
return Network.create(async (params, variables) => {
const response = await fetch('/api/graphql', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: params.text,
variables,
}),
});
const json = await response.text();
return JSON.parse(json);
});
}
let clientEnv: Environment | undefined;
export function getClientEnvironment() {
if (typeof window === 'undefined') return null;
if (clientEnv == null) {
clientEnv = new Environment({
network: createClientNetwork(),
store: new Store(new RecordSource()),
isServer: false,
});
}
return clientEnv;
}
and then createServerEnvironment
:
import { graphql } from 'graphql';
import { GraphQLResponse, Network } from 'relay-runtime';
// Relay is not prescriptive about how GraphQL requests are made.
// This is an example showing how to request GraphQL data.
// You should fill this in with how to make requests to your GraphQL
// API of choice.
import { makeGraphQLRequest } from './my_graphql_api';
export function createServerNetwork() {
return Network.create(async (text, variables) => {
const results = await makeGraphQLRequest(text, variables);
return JSON.parse(JSON.stringify(results)) as GraphQLResponse;
});
}
// Optional: this function can take a token used for authentication and pass it into `createServerNetwork`.
export function createServerEnvironment() {
return new Environment({
network: createServerNetwork(),
store: new Store(new RecordSource()),
isServer: true,
});
}
Configuring _app
// pages/_app.tsx
import { RelayEnvironmentProvider } from 'react-relay/hooks';
import { useRelayNextjs } from 'relay-nextjs/app';
import { getClientEnvironment } from '../lib/client_environment';
function MyApp({ Component, pageProps }: AppProps) {
const { env, ...relayProps } = useRelayNextjs(pageProps, {
createClientEnvironment: () => getClientSideEnvironment()!,
});
return (
<>
<RelayEnvironmentProvider environment={env}>
<Component {...pageProps} {...relayProps} />
</RelayEnvironmentProvider>
</>
);
}
export default MyApp;
Usage in a Page
// src/pages/user/[uuid].tsx
import { withRelay, RelayProps } from 'relay-nextjs';
import { graphql, usePreloadedQuery } from 'react-relay/hooks';
// The $uuid variable is injected automatically from the route.
const ProfileQuery = graphql`
query profile_ProfileQuery($uuid: ID!) {
user(id: $uuid) {
id
firstName
lastName
}
}
`;
function UserProfile({ preloadedQuery }: RelayProps<{}, profile_ProfileQuery>) {
const query = usePreloadedQuery(ProfileQuery, preloadedQuery);
return (
<div>
Hello {query.user.firstName} {query.user.lastName}
</div>
);
}
function Loading() {
return <div>Loading...</div>;
}
export default withRelay(UserProfile, UserProfileQuery, {
// Fallback to render while the page is loading.
// This property is optional.
fallback: <Loading />,
// Create a Relay environment on the client-side.
// Note: This function must always return the same value.
createClientEnvironment: () => getClientEnvironment()!,
// Gets server side props for the page.
serverSideProps: async (ctx) => {
// This is an example of getting an auth token from the request context.
// If you don't need to authenticate users this can be removed and return an
// empty object instead.
const { getTokenFromCtx } = await import('lib/server/auth');
const token = await getTokenFromCtx(ctx);
if (token == null) {
return {
redirect: { destination: '/login', permanent: false },
};
}
return { token };
},
// Server-side props can be accessed as the second argument
// to this function.
createServerEnvironment: async (
ctx,
// The object returned from serverSideProps. If you don't need a token
// you can remove this argument.
{ token }: { token: string }
) => {
const { createServerEnvironment } = await import('lib/server_environment');
return createServerEnvironment(token);
},
});