React + Apollo Client + GraphQL Yoga
This guide connects three pieces: a GraphQL Yoga server that understands a schema, an Apollo Client that sends queries and caches the result, and a React component that renders what comes back. The goal is to see the whole path from a field in a schema to a value on the screen.
The server
Yoga turns a schema and a set of resolvers into a fetchable endpoint. The schema declares what can be asked for. The resolvers decide what the answer is.
import { createServer } from "node:http";
import { createSchema, createYoga } from "graphql-yoga";
const lessons = [
{ id: "1", title: "Variables", path: "/complete-javascript/2018/12/17/variables", runtime: "reading" }
];
const schema = createSchema({
typeDefs: `
type Query {
lesson(id: ID!): Lesson
}
type Lesson {
id: ID!
title: String!
path: String!
runtime: String
}
`,
resolvers: {
Query: {
lesson: (_, { id }) => lessons.find((lesson) => lesson.id === id)
}
}
});
createServer(createYoga({ schema })).listen(4000);
The server is now listening on port 4000. The GraphQL endpoint is available at /graphql, so the full address is http://localhost:4000/graphql.
The client
Apollo Client needs two things: a link that knows where the server lives, and a cache that stores the results. The provider makes the client available to every component below it.
import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
import { ApolloProvider } from "@apollo/client/react";
const client = new ApolloClient({
link: new HttpLink({ uri: "http://localhost:4000/graphql" }),
cache: new InMemoryCache()
});
export function App({ children }) {
return <ApolloProvider client={client}>{children}</ApolloProvider>;
}
The query
The gql tag parses the query string. useQuery runs it, tracks loading and error states, and returns the data in the shape the query asked for.
import { gql, useQuery } from "@apollo/client";
const LESSON = gql`
query Lesson($id: ID!) {
lesson(id: $id) {
title
path
}
}
`;
export function Lesson({ id }) {
const { data, loading, error } = useQuery(LESSON, { variables: { id } });
if (loading) return <p>Loading...</p>;
if (error) return <p>Something went wrong.</p>;
return <h2>{data.lesson.title}</h2>;
}
What to notice
The component does not know how the data is stored. It only knows the shape of the query. The server does not know how the component renders. It only knows the schema. That separation is the point of GraphQL, and it is why the schema is worth designing before the first resolver is written.
The cache is the other half of the story. Apollo can reuse a result when the same object is requested again, which keeps the UI responsive and reduces repeated network work.
Where to go next
Read the Objects lesson for the data shapes on the server, then try the Promises lesson to understand the async work behind a query.
References and further reading
- GraphQL: LearnThe official introduction to schemas and queries.
- Apollo Client: React docsSetup, queries, and caching.
- GraphQL YogaThe server used in the example.