Why Apollo Client?
Why choose Apollo Client to manage your data?
Data management shouldn't have to be so difficult! If you're wondering how to simplify managing remote and local data in your React application, then you've come to the right place. Through practical examples inspired by our example app Pupstagram, you'll learn how Apollo's intelligent caching and declarative approach to data fetching can help you iterate faster while writing less code. Let's jump right in! 🚀
Declarative data fetching
With Apollo's declarative approach to data fetching, all of the logic for retrieving your data, tracking loading and error states, and updating your UI is encapsulated by the useQuery
Hook. This encapsulation makes integrating query results into your presentational components a breeze! Let's see what this looks like in practice with React Apollo:
1function Feed() {
2 const { loading, error, data } = useQuery(GET_DOGS);
3 if (error) return <Error />;
4 if (loading || !data) return <Fetching />;
5
6 return <DogList dogs={data.dogs} />;
7}
1const Feed = () => (
2 <Query query={GET_DOGS}>
3 {({ loading, error, data }) => {
4 if (error) return <Error />
5 if (loading || !data) return <Fetching />;
6
7 return <DogList dogs={data.dogs} />
8 }}
9 </Query>
10)
Here we're using the useQuery
Hook to fetch some dogs from our GraphQL server and display them in a list. useQuery
leverages React's Hooks API to bind a query to our component and render it based on the results of our query. Once our data comes back, our <DogList />
component will update reactively with the data it needs.
Apollo Client takes care of the request cycle from start to finish, including tracking loading and error states for you. There's no middleware to set up or boilerplate to write before making your first request, nor do you need to worry about transforming and caching the response. All you have to do is describe the data your component needs and let Apollo Client do the heavy lifting. 💪
You'll find that when you switch to Apollo Client, you'll be able to delete a lot of unnecessary code related to data management. The exact amount will vary depending on your application, but some teams have reported up to thousands of lines. While you'll find yourself writing less code with Apollo, that doesn't mean you have to compromise on features! Advanced features like optimistic UI, refetching, and pagination are all easily accessible through useQuery
options.
Zero-config caching
One of the key features that sets Apollo Client apart from other data management solutions is its normalized cache. Just by setting up Apollo Client, you get an intelligent cache out of the box with no additional configuration required. From the home page of the Pupstagram example app, click one of the dogs to see its detail page. Then, go back to the home page. You'll notice that the images on the home page load instantaneously, thanks to the Apollo cache.
1import ApolloClient from 'apollo-boost';
2
3// the Apollo cache is set up automatically
4const client = new ApolloClient();
Caching a graph is no easy task, but we've spent two years focused on solving it. Since you can have multiple paths leading to the same data, normalization is essential for keeping your data consistent across multiple components. Let's look at some practical examples:
1const GET_ALL_DOGS = gql`
2 query {
3 dogs {
4 id
5 breed
6 displayImage
7 }
8 }
9`;
10
11const UPDATE_DISPLAY_IMAGE = gql`
12 mutation UpdateDisplayImage($id: String!, $displayImage: String!) {
13 updateDisplayImage(id: $id, displayImage: $displayImage) {
14 id
15 displayImage
16 }
17 }
18`;
The query, GET_ALL_DOGS
, fetches a list of dogs and their displayImage
. The mutation, UPDATE_DISPLAY_IMAGE
, updates a single dog's displayImage
. If we update the displayImage
on a specific dog, we also need that item on the list of all dogs to reflect the new data. Apollo Client splits out each object in a GraphQL result with a __typename
and an id
property into its own entry in the Apollo cache. This guarantees that returning a value from a mutation with an id will automatically update any queries that fetch the object with the same id. It also ensures that two queries which return the same data will always be in sync.
Features that are normally complicated to execute are trivial to build with the Apollo cache. Let's go back to our GET_ALL_DOGS
query from the previous example that displays a list of dogs. What if we want to transition to a detail page for a specific dog? Since we've already fetched information on each dog, we don't want to refetch the same information from our server. With cache redirects, the Apollo cache lets us connect the dots between two queries so we don't have to fetch information that we know is already available.
Here's what our query for one dog looks like:
1const GET_DOG = gql`
2 query {
3 dog(id: "abc") {
4 id
5 breed
6 displayImage
7 }
8 }
9`;
Here's our cache redirect, which we can set up easily by specifying a map on the cacheRedirects
property of the apollo-boost
client. The cache redirect returns a key that the query can use to look up the data in the cache.
1import ApolloClient from 'apollo-boost';
2
3const client = new ApolloClient({
4 cacheRedirects: {
5 Query: {
6 dog: (_, { id }, { getCacheKey }) => getCacheKey({ id, __typename: 'Dog' })
7 }
8 }
9})
Combine local & remote data
Thousands of developers have told us that Apollo Client excels at managing remote data, which equates to roughly 80% of their data needs. But what about local data (like global flags and device API results) that make up the other 20% of the pie? Apollo Client includes local state management features out of the box, that allow you to use your Apollo cache as the single source of truth for data in your application.
Managing all your data with Apollo Client allows you to take advantage of GraphQL as a unified interface to all of your data. This enables you to inspect both your local and remote schemas in Apollo DevTools through GraphiQL.
1const GET_DOG = gql`
2 query GetDogByBreed($breed: String!) {
3 dog(breed: $breed) {
4 images {
5 url
6 id
7 isLiked @client
8 }
9 }
10 }
11`;
By leveraging Apollo Client's local state functionality, you can add client-side only fields to your remote data seamlessly and query them from your components. In this example, we're querying the client-only field isLiked
alongside our server data. Your components are made up of local and remote data, now your queries can be too!
Vibrant ecosystem
Apollo Client is easy to get started with, but extensible for when you need to build out more advanced features. If you need custom functionality that isn't covered with apollo-boost
, such as app-specific middleware or cache persistence, you can create your own client by plugging in an Apollo cache and chaining together your network stack with Apollo Link.
This flexibility makes it simple to create your dream client by building extensions on top of Apollo. We're always really impressed by what our contributors have built on top of Apollo - check out some of their packages:
Apollo Link community links: Pluggable links created by the community
apollo-cache-persist: Simple persistence for your Apollo cache (@jamesreggio)
apollo-storybook-decorator: Wrap your React Storybook stories with Apollo Client (@abhiaiyer91)
AppSync by AWS: Amazon's real-time GraphQL client uses Apollo Client under the hood
When you choose Apollo to manage your data, you also gain the support of our amazing community. There are thousands of developers in our Apollo Spectrum community for you to share ideas with. You can also read articles on best practices and our announcements on the Apollo blog, updated frequently.
Case studies
Companies ranging from enterprises to startups trust Apollo Client to power their most critical web & native applications. If you'd like to learn more about how transitioning to GraphQL and Apollo simplified their engineers' workflows and improved their products, check out these case studies:
The New York Times: Learn how The New York Times switched from Relay to Apollo & implemented features in their app such as SSR and persisted queries
Express: Easy-to-use pagination with Apollo helped improve the Express eCommerce team's key product pages
Major League Soccer: MLS' switch from Redux to Apollo for state management enabled them to delete nearly all of their Redux code
Expo: Developing their React Native app with Apollo allowed the Expo engineers to focus on improving their product instead of writing data fetching logic
KLM: Learn how the KLM team scaled their Angular app with GraphQL and Apollo
If your company is using Apollo Client in production, we'd love to feature a case study on our blog! Please get in touch via Spectrum so we can learn more about how you're using Apollo. Alternatively, if you already have a blog post or a conference talk that you'd like to feature here, please send in a PR.