next-relay-bridge v2.0.4
Next Relay Bridge
Middleware to simplify using Next.js with the Relay GraphQL client.
What is it?
Next Relay Bridge makes it easy to server-side render Next.js pages that rely on Relay data. With the utilities that Next Relay Bridge provides, you can load Relay queries server-side and use the resultant data to initialize your Relay store on the client.
On the server, we await your queries to create the Relay store's initial state. This initial state is sent to the client, which uses it to hydrate the Relay environment's initial store.
On the client, on first app render, we create the client-side Relay environment with the initial data that was sent by the server. The initial page that was requested can use this hydrated store to get its data, so we can render immediately without any data fetches.
On subsequent client-side page navigations, we fetch the data client-side so that you can use Suspense as necessary for progrsesive loading.
Adding to an existing project
Install Next Relay Bridge with
yarn add next-relay-bridge
ornpm -i next-relay-bridge
.Create a file to initialze Next Relay Bridge. In this example, we'll refer to this file as
"../path/to/bridge"
.In this file, create the
withAppBridge
andwithPageBridge
utilities that you'll use to interface with the system using thecreateNextRelayBridge
function. ExportwithAppBridge
andwithPageBridge
from this file so we can use it in our application.
// path/to/bridge.js
import { createNextRelayBridge } from "next-relay-bridge";
const { withAppBridge, withPageBridge } = createNextRelayBridge({
getServerEnvironment: () => {
/**
* This function should return the Relay environment that we'll use on the server.
*
* @see: /example/relay/serverEnvironment.ts
*/
},
getClientEnvironment: (initialStore) => {
/**
* This function should return the Relay environment that we'll use on the client.
* This environment must initialize it's store with the incoming `initialStore` value
* that this function receives.
*
* @see: /example/relay/clientEnvironment.ts
*/
},
});
export { withAppBridge, withPageBridge };
- Wrap your Next.js
_app
component withwithAppBridge
as seen below. Your app component will now receive an additionalrelayEnvironment
prop. Pass this to your<RelayEnvironmentProvider>
.
import { RelayEnvironmentProvider } from "react-relay/hooks";
import { withAppBridge } from "../path/to/bridge";
function MyApp({ Component, pageProps, relayEnvironment }) {
return (
<RelayEnvironmentProvider environment={relayEnvironment}>
<Component {...pageProps} />
</RelayEnvironmentProvider>
);
}
export default withAppBridge({
AppComponent: MyApp,
});
- To use this on a page component, wrap your page component with
withPageBridge
as seen below.withPageBridge
takes an object as its argument whereAppComponent
should be your page component, andgetInitialProps
should be an async function that returns your page component's initial props.
getInitialProps
receives an object as its argument, where context
is the Next.js context object, and preloadQuery
is an async function that you use to preload any queries that you want to pass to your page component.
import { usePreloadedQuery } from "react-relay";
import { graphql } from "relay-runtime"; //`
import { SafeSuspense } from "next-relay-bridge";
import { withPageBridge } from "../path/to/bridge";
const somePageQuery = graphql`
query somePageQuery {
viewer {
example
}
}
`;
function SomePageContent({
name,
someQueryReference
}) {
const data = usePreloadedQuery(
somePageQuery,
someQueryReference
);
return (
<div>
My name is {name} and my data is: {JSON.stringify(data)}
</div>
);
}
function SomePage(props) {
return (
<SafeSuspense fallback="Loading...">
<SomePageContent {...props} />
</SafeSuspense>
);
}
export default withPageBridge({
PageComponent: SomePage,
getInitialProps: async ({ context, preloadQuery }) => {
// Use the incoming `preloadQuery` function to load queries. You _must_ await these.
const someQueryReference = await preloadQuery(somePageQuery, {});
// Return any initial props that your page component needs. Next Relay Bridge will introspect
// the props and only process props that have been ran through `preloadQuery`.
return {
name: 'Friend',
someQueryReference
}
}
});
That's it! When a user navigates to SomePage
directly, we'll wait until the queries have resolved before sending the page up to the client. The client will use the server-side data to initialize its store, and you'll be able to display the whole page without any additional data requests.
When navigating to SomePage
on the client via client-side routing, the client will fetch the data and your page will suspend while the data is being fetched.
Creating a new Next.js project with Relay and Next Relay Brdige
Detailed instructions coming soon...
Additional features
SafeSuspense
next-relay-bridge
exports aSafeSuspense
component that you can use to suspend while data is being fetched on the client. Currently, we can't useReact.Suspense
on the server, so this component wraps its children with aReact.Fragment
if on the server, or aReact.Suspense
if on the client.- If your
SafeSuspense
children will suspend on the server (something that is not yet yet supported by ReactDOMServer), passSafeSuspense
aclientOnly={true}
prop so that it will rendernull
on the server.
- Redirects
- If you need to redireect from a page component using
withPageBridge
, yourgetInitialProps
function can return an object that has aredirect
value. It should match the shape of{ destination: string, permanent?: boolean | number }
. Ifpermanent
isfalse
, it will be treated as a 307 redirect. Ifpermanent
is true, it'll be a 308. You can also passpermanent
a redirect status code to set it directly.
- If you need to redireect from a page component using