All Projects → RevereCRE → relay-nextjs

RevereCRE / relay-nextjs

Licence: MIT license
⚡️ Relay Hooks integration for Next.js apps

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
CSS
56736 projects

Projects that are alternatives of or similar to relay-nextjs

next
(Work in progress) The rewritten version of the original PizzaQL 🍕
Stars: ✭ 45 (-73.68%)
Mutual labels:  next
itdagene-webapp
Next-gen itdagene webapp
Stars: ✭ 15 (-91.23%)
Mutual labels:  relay
iron-session
🛠 Node.js stateless session utility using signed and encrypted cookies to store data. Works with Next.js, Express, NestJs, Fastify, and any Node.js HTTP framework.
Stars: ✭ 1,729 (+911.11%)
Mutual labels:  next
react-relay-appsync
AppSync for Relay
Stars: ✭ 19 (-88.89%)
Mutual labels:  relay
social-relay
Public post relay for the Diaspora federated social network protocol
Stars: ✭ 27 (-84.21%)
Mutual labels:  relay
avuef
Actions on the Flow - Vue
Stars: ✭ 15 (-91.23%)
Mutual labels:  next
next-microcms-sample
Next.js + microCMS SSG example.
Stars: ✭ 14 (-91.81%)
Mutual labels:  next
trouble-training
FullStack DDD/CQRS with GraphQL workshop including distributed tracing and monitoring. This shows the configuration from React frontend to .Net backend.
Stars: ✭ 271 (+58.48%)
Mutual labels:  relay
periqles
React form library for Relay and Apollo
Stars: ✭ 124 (-27.49%)
Mutual labels:  relay
safe-relay-service
Relay Tx Service for Gnosis Safe
Stars: ✭ 48 (-71.93%)
Mutual labels:  relay
next-react-boilerplate
🔥 NextJS with additional tech feature like react-boilerplate. Demo >>
Stars: ✭ 20 (-88.3%)
Mutual labels:  next
nextjs-breadcrumbs
A dynamic, highly customizable breadcrumbs component for Next.js
Stars: ✭ 70 (-59.06%)
Mutual labels:  next
react-reads
Recommended tools, curated articles to learn more about react-ecosystem and some common implementation logics in react,ts,next.
Stars: ✭ 19 (-88.89%)
Mutual labels:  next
opcua-esp32
Embedded OPC UA Server on ESP32 based on open62541 stack
Stars: ✭ 82 (-52.05%)
Mutual labels:  relay
bradgarropy.com
🏠 my home on the web
Stars: ✭ 58 (-66.08%)
Mutual labels:  next
graphql-hackathon
Repo for starter kits and samples for the GraphQL Community Hackathon
Stars: ✭ 25 (-85.38%)
Mutual labels:  relay
next-size
Next.js plugin to print browser assets sizes
Stars: ✭ 39 (-77.19%)
Mutual labels:  next
isomorphic-relay-app
Example isomorphic React-Relay-(Modern / Classic)-Router app and helper lib that connects to Artsy's GraphQL service
Stars: ✭ 13 (-92.4%)
Mutual labels:  relay
personal-website
Personal website – made with Next.js, Preact, MDX, RMWC, & Vercel
Stars: ✭ 16 (-90.64%)
Mutual labels:  next
react-native-relay
🚀 demo React Native app using React Navigation and Relay with mutations and subscriptions
Stars: ✭ 20 (-88.3%)
Mutual labels:  relay

Revere CRE is hiring! Interested in working on the cutting edge of frontend?
Reach out to [email protected] for more information.

Relay + Next.js

npm version npm downloads npm bundle size

Documentation | Discussion | Latest Releases

relay-nextjs is the best way to use Relay and Next.js in the same project! It supports incremental migration, is suspense ready, and is run in production by major companies.

Overview

relay-nextjs wraps page components, a GraphQL query, and some helper methods to automatically hook up data fetching using Relay. On initial load a Relay environment is created, the data is fetched server-side, the page is rendered, and resulting state is serialized as a script tag. On boot in the client a new Relay environment and preloaded query are created using that serialized state. Data is fetched using the client-side Relay environment on subsequent navigations.

Getting Started

Install using npm or your other favorite package manager:

$ npm install relay-nextjs

relay-nextjs must be configured in both a custom _document and _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 { getRelaySerializedState } from 'relay-nextjs';
import { withHydrateDatetime } from 'relay-nextjs/date';
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, withHydrateDatetime);
  });
}

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(getRelaySerializedState()?.records)),
      isServer: false,
    });
  }

  return clientEnv;
}

and then createServerEnvironment:

import { graphql } from 'graphql';
import { withHydrateDatetime } from 'relay-nextjs/date';
import { GraphQLResponse, Network } from 'relay-runtime';
import { schema } from 'lib/schema';

export function createServerNetwork() {
  return Network.create(async (text, variables) => {
    const context = {
      token,
      // More context variables here
    };

    const results = await graphql({
      schema,
      source: text.text!,
      variableValues: variables,
      contextValue: context,
    });

    const data = JSON.parse(
      JSON.stringify(results),
      withHydrateDatetime
    ) as GraphQLResponse;

    return data;
  });
}

export function createServerEnvironment() {
  return new Environment({
    network: createServerNetwork(),
    store: new Store(new RecordSource()),
    isServer: true,
  });
}

Note in the example server environment we’re executing against a local schema but you may fetch from a remote API as well.

Configuring _document

// pages/_document.tsx
import { createRelayDocument, RelayDocument } from 'relay-nextjs/document';

interface DocumentProps {
  relayDocument: RelayDocument;
}

class MyDocument extends Document<MyDocumentProps> {
  static async getInitialProps(ctx: DocumentContext) {
    const relayDocument = createRelayDocument();

    const renderPage = ctx.renderPage;
    ctx.renderPage = () =>
    renderPage({
      enhanceApp: (App) => relayDocument.enhance(App),
    });

    const initialProps = await Document.getInitialProps(ctx);

    return {
      ...initialProps,
      relayDocument,
    };
  }

  render() {
    const { relayDocument } = this.props;

    return (
      <Html>
        <Head>
          {/* ... */}
          <relayDocument.Script />
        </Head>
        {/* ... */}
      </Html>
    );
  }
}

Configuring _app

// pages/_app.tsx
import { RelayEnvironmentProvider } from 'react-relay/hooks';
import { getInitialPreloadedQuery, getRelayProps } from 'relay-nextjs/app';
import { getClientEnvironment } from ../lib/client_environment‘;

const clientEnv = getClientEnvironment();
const initialPreloadedQuery = getInitialPreloadedQuery({
  createClientEnvironment: () => getClientEnvironment()!,
});

function MyApp({ Component, pageProps }: AppProps) {
  const relayProps = getRelayProps(pageProps, initialPreloadedQuery);
  const env = relayProps.preloadedQuery?.environment ?? clientEnv!;

  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);
  },
});
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].