React Hooks + GraphQL 项目实战
约 627 字大约 2 分钟
GraphQLReactApollo Client
2026-04-08
本文介绍如何在 React 项目中使用 Apollo Client 的 Hooks API 消费 GraphQL 接口。
1. 安装
pnpm add @apollo/client graphql2. 初始化客户端
src/apollo.ts:
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
const httpLink = createHttpLink({
uri: '/graphql',
})
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('token')
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
}
})
export const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
})3. 注入 Provider
src/main.tsx:
import { ApolloProvider } from '@apollo/client'
import { client } from './apollo'
ReactDOM.createRoot(document.getElementById('root')!).render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
)4. useQuery
import { gql, useQuery } from '@apollo/client'
const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`
interface User {
id: string
name: string
email: string
}
export function UserList() {
const { loading, error, data, refetch } = useQuery<{ users: User[] }>(GET_USERS)
if (loading) return <p>加载中...</p>
if (error) return <p>出错了: {error.message}</p>
return (
<div>
<button onClick={() => refetch()}>刷新</button>
<ul>
{data!.users.map((u) => (
<li key={u.id}>
{u.name} — {u.email}
</li>
))}
</ul>
</div>
)
}常用配置
fetchPolicy:cache-first(默认)、network-only、cache-and-network、no-cachepollInterval:轮询间隔(ms)skip:条件跳过查询variables:传递查询变量
useQuery(GET_USER, {
variables: { id },
skip: !id,
fetchPolicy: 'cache-and-network',
})5. useMutation
import { gql, useMutation } from '@apollo/client'
const CREATE_POST = gql`
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
}
}
`
export function CreatePostForm() {
const [createPost, { loading, error }] = useMutation(CREATE_POST, {
// 变更成功后刷新列表
refetchQueries: ['GetPosts'],
// 或手动更新缓存
update(cache, { data: { createPost } }) {
cache.modify({
fields: {
posts(existing = []) {
return [...existing, createPost]
},
},
})
},
})
const handleSubmit = async (input: { title: string; content: string }) => {
await createPost({
variables: { input: { ...input, authorId: '1' } },
})
}
return <form onSubmit={/* ... */}>{/* ... */}</form>
}6. useSubscription
import { gql, useSubscription } from '@apollo/client'
const POST_CREATED = gql`
subscription {
postCreated {
id
title
}
}
`
export function PostNotifier() {
const { data, loading } = useSubscription(POST_CREATED)
if (loading) return null
return <div>新文章:{data.postCreated.title}</div>
}需在客户端额外配置 GraphQLWsLink:
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
import { createClient } from 'graphql-ws'
import { split, HttpLink } from '@apollo/client'
import { getMainDefinition } from '@apollo/client/utilities'
const wsLink = new GraphQLWsLink(createClient({ url: 'ws://localhost:4000/graphql' }))
const httpLink = new HttpLink({ uri: '/graphql' })
const splitLink = split(
({ query }) => {
const def = getMainDefinition(query)
return def.kind === 'OperationDefinition' && def.operation === 'subscription'
},
wsLink,
httpLink,
)7. 缓存与归一化
Apollo Client 的 InMemoryCache 使用 __typename + id 作为对象唯一键对响应结果做归一化存储。这带来两个好处:
- 不同查询返回的同一实体会自动合并
- 变更一个对象时,所有依赖它的查询都会自动更新
手动读/写缓存:
// 读
const data = client.readQuery({ query: GET_USERS })
// 写
client.writeQuery({
query: GET_USERS,
data: { users: [...data.users, newUser] },
})8. 代码生成(推荐)
使用 @graphql-codegen/cli 基于 Schema 和 .graphql 文件自动生成 TypeScript 类型与 Typed Hooks,避免手写类型出错。
pnpm add -D @graphql-codegen/cli @graphql-codegen/client-presetcodegen.ts:
import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'http://localhost:4000/graphql',
documents: ['src/**/*.{ts,tsx}'],
generates: {
'./src/gql/': {
preset: 'client',
},
},
}
export default config运行 pnpm graphql-codegen 后即可在组件里使用全类型安全的查询文档。
