Apollo Client, now with React Hooks
Hugh Willson
Our mission is to make Apollo Client the most modern and frictionless state management solution for React developers. As the React community has evolved and pioneered new UI development best practices over time, we’ve ensured that Apollo Client adopts and upholds those practices. In keeping with that tradition, today we’re thrilled to announce the addition of React Hooks to Apollo Client! 🚀
Introduced in React 16.8, Hooks are a new way to write stateful components while avoiding the pitfalls of classes. Apollo Client now includes three hooks that you can drop into your app, anywhere you currently use a corresponding higher-order component or render prop component: useQuery
, useMutation
, and useSubscription
. These hooks are simple to get started with, and they have many advantages over the previous APIs, including bundle size reductions and less boilerplate code.
One of the things we love most about React is that the core team and the community are always striving to improve the React developer experience, and Hooks are a prime example of this. We encourage everyone to start using them!
Getting started
If you’re looking to start a new Apollo project, we recommend installing the following package after you’ve set up your Apollo Client instance:
npm install @apollo/react-hooks
This package exports the ApolloProvider
component to connect the client to your React app, just like the old API.
If you already have an Apollo project, you have a couple options depending on how you want to transition to hooks. Read the migration guide to learn more about upgrading.
Why Hooks are the future ⚓️
Apollo Client still supports its higher-order component and render prop APIs, and it will support them for a while. Going forward, we think hooks are the best way to fetch data with Apollo Client. While you don’t need to migrate all of your old components right away, you should adopt hooks for new components. Here’s why:
Less data management code
Hooks reduce boilerplate and unnecessary data management code, which leads to smaller components that are easier to reason about. You no longer have to understand how to compose higher-order components or trace complicated render prop logic. Fetching data is as straightforward as calling a single useQuery
function:
const LAST_LAUNCH = gql`
query lastLaunch {
launch {
id
timestamp
}
}
`;
export function LastLaunch() {
const { loading, data } = useQuery(LAST_LAUNCH);
return (
<div>
<h1>Last Launch</h1>
{loading ? <p>Loading</p> : <p>Timestamp: {data.launch.timestamp}</p>}
</div>
);
}
See the Apollo platform tutorial app for a working example of Apollo Client hooks.
Multiple mutations
When you’re working with multiple mutations in a single component, higher-order components and render props can produce code that is difficult to understand. With the render prop API, the nesting of multiple Mutation
components creates a false sense of hierarchy. The new useMutation
hook avoids this issue entirely since we’re simply calling a function. The example below demonstrates how multiple mutations and a query can interact with each other, all from within the same component:
function Message() {
const [saveMessage, { loading }] = useMutation(SAVE_MESSAGE);
const [deleteMessage] = useMutation(DELETE_MESSAGE);
const { data } = useQuery(GET_MESSAGE);
return (
<div>
<p>
{loading
? 'Loading ...'
: `Message: ${data && data.message ? data.message.content : ''}`}
</p>
<p>
<button onClick={() => saveMessage()}>Save</button>
<button onClick={() => deleteMessage()}>Delete</button>
</p>
</div>
);
}
You can see multiple mutations in action here. This example app also includes a similar component built using render props, which you can compare with the hooks approach.
Improved TypeScript support
It’s no secret we’re huge fans of TypeScript at Apollo. Combined with automatic type definitions generated by the Apollo CLI, the new hooks make writing type-safe React components even better than before. Here’s what fetching data with Apollo Client’s useQuery
and TypeScript looks like:
import { RocketData, RocketVars } from './types';
const GET_ROCKET_INVENTORY = gql`
query getRocketInventory($year: Int!) {
rocketInventory(year: $year) {
id
year
}
}
`;
export function RocketInventoryList() {
const { loading, data } = useQuery<RocketData, RocketVars>(
GET_ROCKET_INVENTORY,
{ variables: { year: 2019 } }
);
return (/* ... show data ... */);
}
More improvements for React developers
Although this release focuses on the new useQuery
, useMutation
, and useSubscription
hooks, we have a few other exciting features to highlight:
50% bundle size reduction
Whereas the react-apollo@2
package is 10.6 kB minified + gzipped, react-apollo@3
is a mere 7.8 kB. What’s more, if you are able to use only the @apollo/react-hooks
package, the bundle size drops to just 5.1 kB, a 50% savings over react-apollo@2
.
Lazy evaluation for queries
The useQuery
hook executes its query as soon as the function is called, which might not always be desirable. Consider a type-ahead input box, for example. You might want to render a component with your search box prepped to receive input, but delay running your search query until the user begins typing. To enable this behavior, use the useLazyQuery
hook, which returns a tuple with an execute
function in the first position:
const [execute, { loading, data }] = useLazyQuery(GET_INVENTORY);
The query won’t run until you call the execute
function, at which point your component will re-render and the normal useQuery
workflow will proceed. Thanks to community member Daniel K. for his ideas on lazy queries!
New API docs
We’ve updated the docs to emphasize hooks as our recommended path for newcomers to Apollo Client. Nevertheless, our documentation still covers render prop components and the higher-order component. Use the new drop-down menu to select your preferred pattern (coming soon: TypeScript support!):
A big thank you to the community ❤️
The Apollo community is absolutely amazing, and this release wouldn’t have happened without their help. We owe many thanks to everyone involved in developing the Apollo hooks API, whether they triaged issues, contributed code, got involved in beta testing, improved the docs, or helped answer questions on Spectrum. We’d also like to give Daniel Trojanowski an extra special shoutout for his tireless efforts on the <a href="https://github.com/trojanowski/react-apollo-hooks" target="_blank" rel="noreferrer noopener">react-apollo-hooks</a>
project, which paved the way for Apollo to officially support a battle-hardened and thoroughly tested hooks API.
To dive in, head over to the updated Apollo Client docs or reach out with any questions in Spectrum. We can’t wait to see what you build with hooks!