Apollo GraphQL中执行Mutation后如何重新获取所有查询?
Apollo GraphQL更新Person后缓存不一致的解决办法
方法1:手动修改归一化缓存
Apollo的缓存是归一化的,每个对象通过__typename+id唯一标识。只要直接修改缓存中对应Person对象的字段,所有引用该对象的查询都会自动同步更新,不用逐个刷新查询。
修改你的useMutation调用,添加update函数:
const [updatePerson] = useMutation(UPDATE_PERSON, { update(cache, { data: { updateOnePerson } }, { variables }) { // 拿到本次更新的字段数据 const newPersonFields = variables.person; // 生成缓存中该Person对象的唯一标识 const personCacheId = cache.identify({ __typename: 'Person', id: updateOnePerson.id }); // 修改缓存中对应字段 cache.modify({ id: personCacheId, fields: { name() { return newPersonFields.name; }, age() { return newPersonFields.age; }, height() { return newPersonFields.height; }, weight() { return newPersonFields.weight; } // 其他需要更新的字段同理添加 } }); } });
这样不管是PERSON_DATA(直接查询单个Person)还是PERSON_NAMES(Family下的Person列表),只要引用了这个Person对象,都会自动获取更新后的值。
方法2:配置全局类型策略(推荐)
提前在Apollo Client初始化时配置typePolicies,让Apollo自动处理缓存合并,不用每次写mutation都手动维护缓存。
- 先修改Mutation的返回值,返回更新后的完整字段(而不只是id):
export const UPDATE_PERSON = graphql(` mutation updatePerson($personId: String!, $person: PersonUpdateInput!) { updateOnePerson(query: { id: $personId }, set: $person) { id name age height weight } } `)
- 在创建ApolloClient时添加类型策略:
import { ApolloClient, InMemoryCache } from '@apollo/client'; const client = new ApolloClient({ uri: '/your-graphql-endpoint', cache: new InMemoryCache({ typePolicies: { Person: { fields: { // 配置字段合并规则:新值优先,没有新值则保留旧值 name: { merge: (existing, incoming) => incoming ?? existing }, age: { merge: (existing, incoming) => incoming ?? existing }, height: { merge: (existing, incoming) => incoming ?? existing }, weight: { merge: (existing, incoming) => incoming ?? existing } } }, Family: { fields: { // 处理Family下的Persons列表,用id匹配合并 persons: { merge(existing = [], incoming) { const mergedList = [...existing]; incoming.forEach(newPerson => { const matchIndex = mergedList.findIndex(p => p.id === newPerson.id); if (matchIndex !== -1) { mergedList[matchIndex] = { ...mergedList[matchIndex], ...newPerson }; } else { mergedList.push(newPerson); } }); return mergedList; } } } } } }) });
配置完成后,每次执行UPDATE_PERSON mutation,Apollo会自动把返回的Person数据合并到缓存中,所有相关查询都会自动更新,无需额外代码。
方法3:动态筛选要刷新的查询
如果偏好使用refetchQueries,可以用函数形式动态筛选当前缓存中与Person相关的查询,避免手动维护查询列表:
const [updatePerson] = useMutation(UPDATE_PERSON, { refetchQueries: ({ queryManager }) => { // 获取缓存中所有活跃的查询 const allQueries = queryManager.getCache().getAllQueries(); // 筛选出名称包含Person的查询(可根据实际情况调整筛选规则) return allQueries .filter(query => { const opDef = query.query.definitions.find(def => def.kind === 'OperationDefinition'); return opDef?.name?.value.toLowerCase().includes('person'); }) .map(query => ({ query: query.query, variables: query.variables })); } });
这种方法会自动刷新所有相关查询,但可能会带来不必要的网络请求,性能上不如前两种方法。
内容的提问来源于stack exchange,提问作者Simon Tran
相关产品推荐
相关产品推荐

