Back to Relay

Quick Start

website/versioned_docs/version-v20.0.0/getting-started/quick-start.md

20.1.16.0 KB
Original Source

This quick start guide will start with a new React app using Vite and show you how to add Relay to it.

:::tip If you'd prefer an automated approach, create-relay-app by Tobias Tengler will walk you through adding Relay to an existing React app via a series of prompts: npm create @tobiastengler/relay-app :::

We will be building a simple app which shows Star Wars movies fetched from the example Star Wars GraphQL API hosted by graphql.org.

Scaffold a React App

We’ll start with a Vite React app using TypeScript.

bash
npm create vite -- --template react-ts

You’ll be prompted for a project name. Type: relay-example

Install Dependencies

bash
cd relay-example

# Runtime dependencies
npm install relay-runtime react-relay
# Dev dependencies
npm install --save-dev babel-plugin-relay graphql relay-compiler
# Types
npm install --save-dev @types/relay-runtime @types/react-relay

Configure Vite to use Relay

Relay uses a Babel plugin to insert code generated by the Relay compiler into your bundle. We can enable the Relay Babel plugin we installed earliery by configuring the React Vite plugin.

tsx
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    // change-line
    react({ babel: { plugins: ["relay"] } })
  ],
})

See Babel Plugin for information about how to configure the Babel plugin for other build systems.

Configure the Relay Compiler

Next we will download the GraphQL schema for the Star Wars GraphQL endpoint.

bash
curl -O https://raw.githubusercontent.com/graphql/swapi-graphql/refs/heads/master/schema.graphql

And define our relay.config.json config file which tells the Relay Compiler which schema file we want it to use and other details about our project.

json
{
  "src": "./src",
  "schema": "./schema.graphql",
  "language": "typescript"
}

See Relay Compiler for more information about configuring and running the Relay compiler.

Configure your Relay Environment

To allow components within our application to fetch GraphQL we configure a Relay Environment to fetch from our test endpoint and add it to React context.

tsx
import { StrictMode, Suspense } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";
import { RelayEnvironmentProvider } from "react-relay";
import { Environment, Network, FetchFunction } from "relay-runtime";

const HTTP_ENDPOINT = "https://graphql.org/graphql/";

const fetchGraphQL: FetchFunction = async (request, variables) => {
  const resp = await fetch(HTTP_ENDPOINT, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ query: request.text, variables }),
  });
  if (!resp.ok) {
    throw new Error("Response failed.");
  }
  return await resp.json();
};

const environment = new Environment({
  network: Network.create(fetchGraphQL),
});

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <RelayEnvironmentProvider environment={environment}>
      <Suspense fallback="Loading...">
        <App />
      </Suspense>
    </RelayEnvironmentProvider>
  </StrictMode>
);

See Relay Environment for an overview of the Relay Environment and how to configure it.

:::tip <RelayEnvironmentProvider> exposes your Environment via React context, so it must wrap your entire application. :::

Define your first Relay component

Finally we can start defining the data we want to fetch and build our UI. Our app will fetch a list of films and render each one using a <Film> component.

tsx
import { AppQuery } from "./__generated__/AppQuery.graphql";
import { graphql, useLazyLoadQuery } from "react-relay";
import Film from "./Film";

export default function App() {
  const data = useLazyLoadQuery<AppQuery>(
    graphql`
      query AppQuery {
        allFilms {
          films {
            id
            ...Film_item
          }
        }
      }
    `,
    {}
  );

  const films = data?.allFilms?.films?.filter((film) => film != null);

  return (
    <div>
      <h1>Star Wars Films</h1>
      {films?.map((film) => (
        <Film key={film.id} film={film} />
      ))}
    </div>
  );
}

Define your first fragment

One of Relay's core principles is that each component should define its own data dependencies. So, we define our <Film> component using a GraphQL Fragment.

typescript
import { graphql, useFragment } from "react-relay";
import type { Film_item$key } from "./__generated__/Film_item.graphql";

export default function FilmListItem(props: { film: Film_item$key; }) {
  const film = useFragment<Film_item$key>(
    graphql`
      fragment Film_item on Film {
        title
        director
      }
    `,
    props.film
  );

  return (
    <li>
      <b>{film.title}</b>: directed by <i>{film.director}</i>
    </li>
  );
}

Compile and run your app

All that’s left is to run the Relay compiler and start your app!

The Relay compiler generates TypeScript types and combines your queries and fragments into optimized representations. You have to run the Relay compiler each time you modify your GraphQL queries or fragments.

:::tip If you have Watchman installed you can run npx relay-compiler --watch to have the compiler run in watch mode, but you'll need to run echo "{}" > .watchmanconfig to create a Watchman root. :::

bash
npx relay-compiler
npm run dev

You should now be able to open your app in a browser: http://localhost:5173/

May the force be with you!