Building a Client-Side Application with React, Apollo, and GraphQL
Why GraphQL + TypeScript?
GraphQL is a query language for APIs that allows clients to request specific data, reducing the amount of data transferred over the network. TypeScript is a statically typed JavaScript superset that helps catch errors early and improves code maintainability. Together, they provide a powerful combination for building robust and efficient applications.
Getting Started with TypeScript, React, and GraphQL
To start, we will create a new React project using create-react-app
with the TypeScript template:
npx create-react-app my-app --template typescript
We will then install the necessary dependencies, including @apollo/client
and graphql
:
npm install @apollo/client graphql
Writing GraphQL Queries and Generating Types
We will write two GraphQL queries: one to fetch a list of launches and another to fetch detailed information about a single launch. We will use the graphql-tag
library to define our queries and the graphql-code-generator
library to generate TypeScript types for our queries.
query Launches {
launches {
id
name
}
}
query Launch($id: ID!) {
launch(id: $id) {
id
name
details
}
}
Initializing Apollo Client
We will initialize the Apollo client and use the ApolloProvider
component to add our client to React’s context:
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'https://api.spacex.com/graphql',
cache: new InMemoryCache(),
});
function App() {
return (
<ApolloProvider client={client}>
{/* app content */}
</ApolloProvider>
);
}
Building Our Components
We will create two components: LaunchList
and LaunchProfile
. The LaunchList
component will display a list of launches, and the LaunchProfile
component will display detailed information about a single launch.
import React from 'eact';
import { useQuery, gql } from '@apollo/client';
const LAUNCHES_QUERY = gql`
query Launches {
launches {
id
name
}
}
`;
function LaunchList() {
const { data, loading, error } = useQuery(LAUNCHES_QUERY);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.launches.map(launch => (
<li key={launch.id}>{launch.name}</li>
))}
</ul>
);
}
Adding User Interaction
We will add functionality to fetch the full launch data when a user clicks on an item in the launch list. We will use the useState
hook to maintain and update the state of the selected launch ID.
import React, { useState } from 'eact';
import { useQuery, gql } from '@apollo/client';
const LAUNCH_QUERY = gql`
query Launch($id: ID!) {
launch(id: $id) {
id
name
details
}
}
`;
function LaunchProfile() {
const [selectedLaunchId, setSelectedLaunchId] = useState(null);
const { data, loading, error } = useQuery(LAUNCH_QUERY, {
variables: { id: selectedLaunchId },
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
{data.launch.name}
<p>{data.launch.details}</p>
</div>
);
}
Code Generation and TypeScript
One of the key benefits of using GraphQL and TypeScript is the ability to generate types automatically. This eliminates the need for manual type definitions and reduces the risk of type-related errors.
Next Steps
To take this application further, we could add pagination to the launch list and explore more data connectivity using additional fields from the SpaceX GraphQL API.