> apollo-client
You are an expert in Apollo Client, the comprehensive GraphQL client for React applications. You help developers fetch data with GraphQL queries and mutations, manage local and remote state with Apollo's normalized cache, implement optimistic UI updates, handle pagination, and configure authentication — providing a complete data management solution for GraphQL-powered apps.
curl "https://skillshub.wtf/TerminalSkills/skills/apollo-client?format=md"Apollo Client — GraphQL Client for React
You are an expert in Apollo Client, the comprehensive GraphQL client for React applications. You help developers fetch data with GraphQL queries and mutations, manage local and remote state with Apollo's normalized cache, implement optimistic UI updates, handle pagination, and configure authentication — providing a complete data management solution for GraphQL-powered apps.
Core Capabilities
Setup and Queries
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery, useMutation } from "@apollo/client";
const client = new ApolloClient({
uri: "https://api.example.com/graphql",
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
posts: { keyArgs: ["filter"], merge(existing = [], incoming) { return [...existing, ...incoming]; } },
},
},
},
}),
headers: { Authorization: `Bearer ${getToken()}` },
});
const GET_POSTS = gql`
query GetPosts($limit: Int!, $offset: Int!, $filter: PostFilter) {
posts(limit: $limit, offset: $offset, filter: $filter) {
id
title
excerpt
author { id name avatar }
createdAt
}
}
`;
function PostList({ filter }: { filter?: PostFilter }) {
const { data, loading, error, fetchMore } = useQuery(GET_POSTS, {
variables: { limit: 10, offset: 0, filter },
});
if (loading) return <Skeleton />;
if (error) return <Error message={error.message} />;
return (
<div>
{data.posts.map(post => <PostCard key={post.id} post={post} />)}
<button onClick={() => fetchMore({ variables: { offset: data.posts.length } })}>
Load more
</button>
</div>
);
}
Mutations with Optimistic Updates
const CREATE_POST = gql`
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) { id title excerpt author { id name } createdAt }
}
`;
function CreatePostForm() {
const [createPost, { loading }] = useMutation(CREATE_POST, {
optimisticResponse: (vars) => ({
createPost: {
__typename: "Post",
id: "temp-id",
title: vars.input.title,
excerpt: vars.input.body.slice(0, 200),
author: { __typename: "User", id: currentUser.id, name: currentUser.name },
createdAt: new Date().toISOString(),
},
}),
update(cache, { data: { createPost } }) {
cache.modify({
fields: {
posts(existing = []) {
const ref = cache.writeFragment({ data: createPost, fragment: POST_FRAGMENT });
return [ref, ...existing];
},
},
});
},
});
const handleSubmit = (data) => createPost({ variables: { input: data } });
return <Form onSubmit={handleSubmit} loading={loading} />;
}
Authentication
import { ApolloClient, createHttpLink, ApolloLink } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { onError } from "@apollo/client/link/error";
const httpLink = createHttpLink({ uri: "/graphql" });
const authLink = setContext((_, { headers }) => ({
headers: { ...headers, authorization: `Bearer ${localStorage.getItem("token")}` },
}));
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors?.some(e => e.extensions?.code === "UNAUTHENTICATED")) {
localStorage.removeItem("token");
window.location.href = "/login";
}
});
const client = new ApolloClient({
link: ApolloLink.from([errorLink, authLink, httpLink]),
cache: new InMemoryCache(),
});
Installation
npm install @apollo/client graphql
Best Practices
- Normalized cache — Apollo normalizes data by
__typename:id; updates to one entity propagate everywhere - Optimistic updates — Provide
optimisticResponsefor mutations; UI updates instantly, corrects on server response - Type policies — Configure
typePoliciesfor pagination merging, field read/write policies - Code generation — Use
graphql-codegento generate TypeScript types from your schema; fully typed queries - Error link — Use
onErrorlink for global error handling (auth refresh, logging, retry) - Fragments — Define reusable fragments for entity fields; share between queries and mutations
- Cache updates — Use
updatefunction orrefetchQueriesafter mutations; prefer cache.modify for performance - Polling and subscriptions — Use
pollIntervalfor simple real-time, WebSocket subscriptions for true real-time
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.