useSWRInfinite结合本地数据mutate后重验证显示旧数据问题
useSWRInfinite 游标分页下修改非首页数据后 mutate 重验证显示旧数据的问题
问题现象
使用 useSWRInfinite 基于游标(最后加载条目ID)实现数据分页时,在第2页及以后编辑或删除条目,调用 mutate 传入修改后的数据并触发重验证,重验证完成后页面会再次显示旧数据;仅执行重验证(不传数据调用 mutate)或仅执行本地修改(禁用重验证)时无此问题。
原因分析
- 直接依赖组件状态更新缓存的风险:当前代码中修改缓存时,直接使用组件渲染时的
repliesPages状态生成更新后的页面数据,这个状态可能并非SWR内部最新的缓存值,导致更新后的缓存存在偏差。 - 重验证时的分页游标逻辑冲突:直接传入修改后的pages到
mutate时,SWR重验证可能基于修改前的旧分页游标(页面最后一个条目ID)请求数据,服务器返回的页面结构与本地修改后的页面不匹配,最终覆盖为旧数据。
解决方案
1. 使用函数式更新缓存
避免直接依赖组件状态,改用mutate的函数式参数,基于SWR内部最新的缓存数据进行修改,确保缓存更新的准确性:
onCommentUpdated={(updatedReply) => { mutateRepliesPages((currentPages) => { if (!currentPages) return currentPages; return currentPages.map(page => { const updatedReplies = page.comments.map(existingReply => existingReply._id === updatedReply._id ? updatedReply : existingReply ); return { ...page, comments: updatedReplies }; }); }); }} onCommentDeleted={() => { mutateRepliesPages((currentPages) => { if (!currentPages) return currentPages; return currentPages.map(page => { const updatedReplies = page.comments.filter(existingReply => existingReply._id !== reply._id ); return { ...page, comments: updatedReplies }; }); }); }}
2. 确保 getPageKey 函数逻辑正确
检查分页键生成函数,确保它能基于最新的页面数据生成正确的游标:
const getPageKey = (pageIndex, previousPageData) => { // 第一页无需游标 if (pageIndex === 0) return [commentId, null]; // 无更多数据时返回 null if (!previousPageData || previousPageData.comments.length === 0) return null; // 取前一页最后一个条目的ID作为下一页游标 const lastReplyId = previousPageData.comments.at(-1)._id; return [commentId, lastReplyId]; };
3. 分离本地更新与重验证(可选)
如果上述方案仍有问题,可以先更新本地缓存(禁用重验证),再手动触发重验证,避免游标逻辑冲突:
onCommentUpdated={(updatedReply) => { // 先更新本地缓存,不触发重验证 mutateRepliesPages((currentPages) => { if (!currentPages) return currentPages; return currentPages.map(page => { const updatedReplies = page.comments.map(existingReply => existingReply._id === updatedReply._id ? updatedReply : existingReply ); return { ...page, comments: updatedReplies }; }); }, { revalidate: false }); // 手动触发重验证 mutateRepliesPages(); }}
验证要点
- 确认服务器端的修改/删除接口已正确处理数据,且分页接口能返回更新后的正确数据。
- 检查重验证时的网络请求,确认请求使用的游标是基于最新页面数据生成的。
内容的提问来源于stack exchange,提问作者Florian Walther
相关产品推荐
相关产品推荐

