ApolloClient是JavaScript生态中主流的GraphQL客户端,内置的InMemoryCache缓存系统默认会将查询返回的数据按照数据ID和字段名进行标准化存储,避免重复请求相同数据,同时减少不必要的网络开销。理解缓存的工作逻辑并掌握对应的管理技巧,能让前端应用的数据流转更加顺畅。

ApolloClient缓存基础规则
ApolloClient的默认缓存策略会为每个查询返回的对象生成唯一标识,默认使用__typename和id字段拼接作为缓存键,存储到内存缓存中。当后续发起相同查询时,会优先从缓存中读取数据,只有缓存不存在或者缓存过期时才会发起网络请求。
我们可以通过配置InMemoryCache的初始化参数来调整基础缓存行为,比如设置缓存的最大存活时间、自定义数据ID生成规则等。以下是一个基础缓存配置示例:
import { ApolloClient, InMemoryCache } from '@apollo/client';
// 自定义数据ID生成规则,适配没有id字段的接口返回
const cache = new InMemoryCache({
dataIdFromObject: (object) => {
// 如果对象有__typename和id,使用默认规则
if (object.__typename && object.id) {
return `${object.__typename}:${object.id}`;
}
// 没有id时返回null,使用默认缓存逻辑
return null;
}
});
const client = new ApolloClient({
uri: 'https://api.ipipp.com/graphql',
cache
});
手动更新缓存的常用技巧
查询后更新缓存
当发起某个查询后,我们可以手动将返回的数据写入缓存,方便后续其他查询直接使用。使用writeQuery方法可以实现这个操作,适合在初始化数据或者主动刷新数据时使用。
import { gql } from '@apollo/client';
// 定义查询语句
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
age
}
}
`;
// 发起查询后手动写入缓存
client.query({
query: GET_USER,
variables: { id: '1' }
}).then((result) => {
// 将查询结果写入缓存
client.writeQuery({
query: GET_USER,
variables: { id: '1' },
data: {
user: result.data.user
}
});
});
变更后更新关联缓存
当执行修改数据的变更操作时,接口返回的新数据可能不会自动同步到已有的缓存中,这时候需要手动更新对应的缓存。可以使用readQuery读取现有缓存,修改后再用writeQuery写回缓存。
import { gql } from '@apollo/client';
// 定义变更语句
const UPDATE_USER_AGE = gql`
mutation UpdateUserAge($id: ID!, $age: Int!) {
updateUserAge(id: $id, age: $age) {
id
name
age
}
}
`;
// 执行变更后更新缓存
client.mutate({
mutation: UPDATE_USER_AGE,
variables: { id: '1', age: 25 }
}).then((result) => {
// 读取现有缓存中的用户数据
const existingUser = client.readQuery({
query: GET_USER,
variables: { id: '1' }
});
// 更新缓存数据
client.writeQuery({
query: GET_USER,
variables: { id: '1' },
data: {
user: {
...existingUser.user,
age: result.data.updateUserAge.age
}
}
});
});
缓存合并策略配置
当同一个缓存键对应的数据被多次写入时,ApolloClient默认会直接覆盖旧数据,我们可以通过配置typePolicies来自定义合并规则,比如合并数组类型的字段、保留旧数据的部分字段等。
以下是一个配置用户列表查询缓存合并的示例,当新查询返回的用户列表时,将新数据追加到旧列表后面:
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
// 配置userList字段的合并策略
userList: {
// 合并函数,existing是旧缓存值,incoming是新查询返回值
merge(existing = [], incoming) {
return [...existing, ...incoming];
}
}
}
}
}
});
缓存清理与重置技巧
在用户退出登录、切换账号等场景下,需要清理所有缓存数据,避免旧数据泄露。ApolloClient提供了resetStore方法可以清空所有缓存,同时重新发起所有活跃的查询。
// 清空所有缓存
client.resetStore().then(() => {
console.log('缓存已清空');
});
// 如果不需要重新发起活跃查询,可以使用clearStore方法
client.clearStore();
如果只需要清理某个特定查询的缓存,可以使用evict方法,指定要清理的缓存字段和变量:
// 清理指定用户的缓存
client.cache.evict({
id: 'User:1', // 对应缓存的数据ID
fieldName: 'user' // 可选,指定要清理的字段
});
// 触发缓存更新通知
client.cache.gc();
常见问题与注意事项
- 如果接口返回的对象没有
id字段,需要自定义dataIdFromObject规则,否则相同结构的对象会被重复缓存,导致数据更新异常。 - 手动更新缓存时,写入的数据结构需要和查询语句定义的字段完全匹配,否则缓存可能无法被正确读取。
- 调用
resetStore后,所有正在进行的查询会被重新发起,需要注意避免不必要的重复请求。
JavaScriptGraphQLApolloClient缓存管理修改时间:2026-07-07 20:24:27