You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

useSWRInfinite结合本地数据mutate后重验证显示旧数据问题

useSWRInfinite 游标分页下修改非首页数据后 mutate 重验证显示旧数据的问题

问题现象

使用 useSWRInfinite 基于游标(最后加载条目ID)实现数据分页时,在第2页及以后编辑或删除条目,调用 mutate 传入修改后的数据并触发重验证,重验证完成后页面会再次显示旧数据;仅执行重验证(不传数据调用 mutate)或仅执行本地修改(禁用重验证)时无此问题。

原因分析

  1. 直接依赖组件状态更新缓存的风险:当前代码中修改缓存时,直接使用组件渲染时的 repliesPages 状态生成更新后的页面数据,这个状态可能并非SWR内部最新的缓存值,导致更新后的缓存存在偏差。
  2. 重验证时的分页游标逻辑冲突:直接传入修改后的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:35:19