如何在Apollo Client Mutation后将实体添加到匹配查询变量的缓存中?
Apollo缓存更新:多变量查询场景的精细处理
针对你遇到的mutation后需更新多组变量查询缓存的问题,以下是几种实用的精细解决方案:
1. 利用字段政策(Field Policies)统一处理缓存逻辑
这是最符合Apollo缓存设计理念的方案,通过定义字段的读取和合并规则,让缓存自动识别哪些列表应包含新条目。
在创建Apollo Client时,为返回工时列表的字段配置自定义政策:
const client = new ApolloClient({ uri: '/graphql', cache: new InMemoryCache({ typePolicies: { Query: { fields: { timeEntries: { // 读取缓存时自动过滤符合当前查询变量的条目 read(existing = [], { args }) { return existing.filter(entry => entry.projectId === args.projectId && entry.startDate >= args.startDate && entry.endDate <= args.endDate ); }, // 新增条目时直接写入根缓存,后续由read逻辑分发到对应查询 merge(existing = [], incoming) { // 去重避免重复添加 const existingIds = new Set(existing.map(e => e.id)); return [...existing, ...incoming.filter(e => !existingIds.has(e.id))]; } } } } } }) });
mutation成功后,只需将新条目写入缓存根节点,无需关心具体查询变量:
const ADD_TIME_ENTRY = gql` mutation AddTimeEntry($input: TimeEntryInput!) { addTimeEntry(input: $input) { id projectId startDate endDate // 其他字段 } } `; // 执行mutation时的update函数 update(cache, { data: { addTimeEntry } }) { cache.writeFragment({ fragment: gql` fragment NewTimeEntry on TimeEntry { id projectId startDate endDate } `, data: addTimeEntry, // 将条目写入Query.timeEntries的根缓存 id: cache.identify({ __typename: 'Query', timeEntries: [] }) }); }
后续任何查询timeEntries的请求,都会通过read函数自动过滤出符合变量条件的条目,包括之前使用过的变量组合。
2. 遍历缓存查询,手动更新符合条件的缓存
如果无法使用字段政策,可以直接解析缓存中的查询键,找出所有匹配新条目的查询并更新:
// mutation的update函数 update(cache, { data: { addTimeEntry } }) { const rootQuery = cache.extract().ROOT_QUERY; const targetQueryName = 'timeEntries'; Object.keys(rootQuery).forEach(queryKey => { // 匹配以目标查询名称开头的缓存键 if (!queryKey.startsWith(`${targetQueryName}(`)) return; try { // 解析查询变量(注意:Apollo缓存的变量字符串格式可能需调整解析逻辑) const varStr = queryKey.slice(targetQueryName.length + 1, -1); // 替换Apollo生成的变量格式为标准JSON const formattedVarStr = varStr.replace(/([a-zA-Z0-9_]+):/g, '"$1":'); const variables = JSON.parse(formattedVarStr); // 判断新条目是否符合当前查询的筛选条件 const isMatch = addTimeEntry.projectId === variables.projectId && addTimeEntry.startDate >= variables.startDate && addTimeEntry.endDate <= variables.endDate; if (isMatch) { // 读取当前查询的缓存数据并追加新条目 const existingData = cache.readQuery({ query: TIME_ENTRIES_QUERY, variables }); cache.writeQuery({ query: TIME_ENTRIES_QUERY, variables, data: { timeEntries: [...existingData.timeEntries, addTimeEntry] } }); } } catch (e) { // 解析失败则跳过该查询 return; } }); }
3. 优化refetchQueries,只刷新符合条件的查询
若你倾向于使用refetch而非手动更新缓存,可以缩小刷新范围,只重新获取包含新条目的查询:
// mutation配置中的refetchQueries refetchQueries: async ({ cache, data }) => { const newEntry = data.addTimeEntry; const rootQuery = cache.extract().ROOT_QUERY; const relevantQueries = []; Object.keys(rootQuery).forEach(queryKey => { if (!queryKey.startsWith('timeEntries(')) return; try { const varStr = queryKey.slice('timeEntries('.length, -1); const formattedVarStr = varStr.replace(/([a-zA-Z0-9_]+):/g, '"$1":'); const variables = JSON.parse(formattedVarStr); if ( newEntry.projectId === variables.projectId && newEntry.startDate >= variables.startDate && newEntry.endDate <= variables.endDate ) { relevantQueries.push({ query: TIME_ENTRIES_QUERY, variables }); } } catch (e) {} }); return relevantQueries; }
内容的提问来源于stack exchange,提问作者wrldtrvllr
相关产品推荐
相关产品推荐

