--- name: apollo-client-patterns description: Use when implementing Apollo Client patterns for queries, mutations, cache management, and local state in React applications. allowed-tools: - Read - Write - Edit - Grep - Glob - Bash --- # Apollo Client Patterns Master Apollo Client for building efficient GraphQL applications with proper query management, caching strategies, and state handling. ## Overview Apollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. It integrates seamlessly with React and provides powerful caching mechanisms. ## Installation and Setup ### Installing Apollo Client ```bash # Install Apollo Client and dependencies npm install @apollo/client graphql # For React applications npm install @apollo/client graphql react # Additional packages npm install graphql-tag @apollo/client/link/error ``` ### Basic Configuration ```javascript // src/apollo/client.js import { ApolloClient, InMemoryCache, createHttpLink, from } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; import { onError } from '@apollo/client/link/error'; const httpLink = createHttpLink({ uri: process.env.REACT_APP_GRAPHQL_URI || 'http://localhost:4000/graphql', }); const authLink = setContext((_, { headers }) => { const token = localStorage.getItem('authToken'); return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '', } }; }); const errorLink = onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) { graphQLErrors.forEach(({ message, locations, path }) => console.error( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}` ) ); } if (networkError) { console.error(`[Network error]: ${networkError}`); } }); const client = new ApolloClient({ link: from([errorLink, authLink, httpLink]), cache: new InMemoryCache({ typePolicies: { Query: { fields: { posts: { merge(existing, incoming) { return incoming; } } } } } }), defaultOptions: { watchQuery: { fetchPolicy: 'cache-and-network', errorPolicy: 'all', }, query: { fetchPolicy: 'network-only', errorPolicy: 'all', }, }, }); export default client; ``` ### Provider Setup ```javascript // src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import { ApolloProvider } from '@apollo/client'; import client from './apollo/client'; import App from './App'; ReactDOM.render( , document.getElementById('root') ); ``` ## Core Patterns ### 1. Basic Queries ```javascript // src/graphql/queries.js import { gql } from '@apollo/client'; export const GET_POSTS = gql` query GetPosts($limit: Int, $offset: Int) { posts(limit: $limit, offset: $offset) { id title body author { id name avatar } createdAt } } `; export const GET_POST = gql` query GetPost($id: ID!) { post(id: $id) { id title body author { id name } comments { id body author { id name } } } } `; // src/components/PostsList.js import React from 'react'; import { useQuery } from '@apollo/client'; import { GET_POSTS } from '../graphql/queries'; function PostsList() { const { loading, error, data, refetch, fetchMore } = useQuery(GET_POSTS, { variables: { limit: 10, offset: 0 }, notifyOnNetworkStatusChange: true, }); if (loading) return

Loading...

; if (error) return

Error: {error.message}

; return (
{data.posts.map(post => (

{post.title}

{post.body}

By {post.author.name}
))}
); } export default PostsList; ``` ### 2. Mutations ```javascript // src/graphql/mutations.js import { gql } from '@apollo/client'; export const CREATE_POST = gql` mutation CreatePost($input: CreatePostInput!) { createPost(input: $input) { id title body author { id name } createdAt } } `; export const UPDATE_POST = gql` mutation UpdatePost($id: ID!, $input: UpdatePostInput!) { updatePost(id: $id, input: $input) { id title body } } `; export const DELETE_POST = gql` mutation DeletePost($id: ID!) { deletePost(id: $id) { id } } `; // src/components/CreatePost.js import React, { useState } from 'react'; import { useMutation } from '@apollo/client'; import { CREATE_POST } from '../graphql/mutations'; import { GET_POSTS } from '../graphql/queries'; function CreatePost() { const [title, setTitle] = useState(''); const [body, setBody] = useState(''); const [createPost, { loading, error }] = useMutation(CREATE_POST, { update(cache, { data: { createPost } }) { const { posts } = cache.readQuery({ query: GET_POSTS }); cache.writeQuery({ query: GET_POSTS, data: { posts: [createPost, ...posts] } }); }, onCompleted: () => { setTitle(''); setBody(''); }, onError: (error) => { console.error('Error creating post:', error); } }); const handleSubmit = (e) => { e.preventDefault(); createPost({ variables: { input: { title, body } } }); }; return (
setTitle(e.target.value)} placeholder="Title" disabled={loading} />