react-apollo:update与updateQuery中的不可变性处理及状态更新问题
好问题!咱们一步步拆解你的疑问,帮你理清React Apollo里updateQuery/update方法的正确用法:
1. 不用工具库简化深层嵌套的不可变更新
你说得没错,深层嵌套的数据做不可变更新确实容易写得冗长,但可以通过提取重复引用或者封装小型复用函数来简化,不用引入Immer之类的第三方库:
方案一:提取重复路径变量
把重复出现的深层属性提取成变量,减少重复书写:
fetchMore({ variables: { cursor }, updateQuery: (previousResult, { fetchMoreResult }) => { // 提取重复的深层引用,避免重复写长路径 const prevArticles = previousResult.author.articles; const newArticles = fetchMoreResult.author.articles; return { ...previousResult, author: { ...previousResult.author, articles: { ...prevArticles, ...newArticles, // 合并顶层属性(比如pageInfo这类分页元数据) edges: [...prevArticles.edges, ...newArticles.edges], // 追加新的文章数据 }, }, }; }, });
方案二:封装小型复用函数
如果项目里有多处类似的嵌套更新,可以写几个极简的工具函数复用,避免重复解构:
// 简易数组追加工具,专门处理分页edges const appendEdges = (prevEdges, newEdges) => [...prevEdges, ...newEdges]; // 简易嵌套对象合并工具 const mergeNested = (prevObj, updates) => ({ ...prevObj, ...updates }); // 在updateQuery中使用 fetchMore({ variables: { cursor }, updateQuery: (previousResult, { fetchMoreResult }) => { return { ...previousResult, author: mergeNested(previousResult.author, { articles: mergeNested(previousResult.author.articles, { ...fetchMoreResult.author.articles, edges: appendEdges( previousResult.author.articles.edges, fetchMoreResult.author.articles.edges ), }), }), }; }, });
2. 直接修改previousResult可行吗?会违背Apollo设计吗?
绝对不建议直接修改previousResult,这完全违背了Apollo Client的核心设计理念:
- Apollo的缓存系统是基于不可变数据模式构建的,
previousResult是缓存数据的快照引用。直接修改它会污染原始缓存,导致Apollo无法通过引用变化追踪数据更新,进而引发组件不渲染、缓存状态混乱等问题。 - 直接修改会带来不可预测的副作用:后续查询可能拿到被篡改的缓存数据,排查bug时会非常棘手。
updateQuery的设计初衷就是让你返回一个全新的不可变数据结构,Apollo会自动对比新旧数据,安全地更新缓存并通知相关组件重新渲染。
哪怕你测试时发现直接修改能临时工作,也会埋下长期隐患,务必坚持返回新的不可变数据。
内容的提问来源于stack exchange,提问作者Robin Wieruch
相关产品推荐
相关产品推荐

