前端使用 GraphQL 客户端的实战选择
前端直接用 fetch 调 GraphQL 当然能跑,但一旦页面上有重复查询、缓存、错误处理、变更更新这些需求,手写代码很快就会变得别扭。GraphQL 的价值不只是'少发几次请求',更麻烦的部分其实在请求之后:怎么缓存,怎么更新本地数据,怎么把类型补齐。
为什么要上客户端库
单纯的 fetch 只能把请求发出去,返回结果也只是一次性的 JSON。对简单页面没问题,但到稍微复杂一点的界面,问题就会露出来:同一份数据被多次请求、不同组件读到的状态不一致、错误分散在各处,后面维护会很累。
客户端库把这些脏活接过去了。常见的收益是这些:
- 减少重复请求
- 只取需要的字段,避免把多余数据带回来
- 配合代码生成拿到 TypeScript 类型
- 统一缓存和失效策略
- 把变更后的数据同步到界面
先看一个不太省心的写法
// 直接使用 fetch 请求 GraphQL async function fetchGraphQL(query, variables) { const response = await fetch('https://api.example.com/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query, variables }), }); const data = await response.json(); if (data.errors) { console.error('GraphQL errors:', data.errors); throw new Error('GraphQL request failed'); } return data.data; } // 重复请求相同数据 async function loadUserAndPosts() { // 第一次请求用户信息 const { user } = await fetchGraphQL(` query GetUser($id: ID!) { user(id: $id) { id name email } } `, { id: 1 }); // 第二次请求用户的帖子 const { user: userWithPosts } = await fetchGraphQL(` query GetUserWithPosts($id: ID!) { user(id: $id) { id posts { id title content } } } `, { id: 1 }); return { user, posts: userWithPosts.posts }; }
这段代码能工作,但也就到'能工作'为止。后面如果要补缓存、重试、局部更新、订阅,代码会越来越散。
Apollo Client:功能最全,也最重
Apollo Client 适合需要完整能力的项目。缓存、请求控制、错误处理、Mutation 更新这些都能直接用,代价是配置和概念也更多一点。
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const client = new ApolloClient({
uri: 'https://api.example.com/graphql',
cache: new InMemoryCache(),
headers: {
authorization: localStorage.getItem('token') ||
}
});
= gql`;
= gql`;
;
{ useQuery, useMutation } ;
() {
{ loading, error, data, refetch } = (, {
: { : userId },
:
});
[createPost, { : creating }] = (, {
() {
{ user } = cache.({
: ,
: { : userId }
});
cache.({
: ,
: { : userId },
: {
: {
...user,
: [...user., createPost]
}
}
});
}
});
(loading) ;
(error) ;
= () => {
({ : { : { title, content, userId } } });
};
(
);
}

