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

React-admin自定义数据提供者下已删记录仍显示在列表的问题

问题描述

我实现了React-Admin自定义数据提供者的delete方法如下:

delete: (resource, { id, previousData }) => {
  return deleteRecord(id).then(res => {
    if (res.data.deleteRecord.success) {
      return { data: previousData };
    }
  });
},

deleteRecord通过Apollo Client成功删除了远程数据,React-Admin会跳转到列表页并显示带“撤销”按钮的通知,但通知消失后,已删除的记录又重新出现在列表里。必须刷新窗口才能看到正确数据,React-Admin自带的刷新功能也没用。

同样的问题在调用deleteMany时也出现,我的deleteMany实现:

deleteMany: (resource, { ids }) => {
      return Promise.all(
        ids.map(id => {
          return deleteRecord(id).then(res => {
            if (res.data.deleteRecord.success) {
              return id;
            }
          });
        })
      ).then(data => ({ data }));
    },

我希望列表本地状态能和数据提供者的删除操作保持一致,试过调整mutationOptions、自定义AppBar、onSuccess和afterDelete生命周期,都没解决。


问题根源

这事儿核心是Apollo Client的缓存没同步更新。你用deleteRecord删掉了远程数据,但Apollo默认不会自动移除缓存里的对应记录。当React-Admin的列表组件重新执行查询时,Apollo优先从缓存读数据,就把已经删掉的记录又加载出来了。

React-Admin本身会根据数据提供者的返回更新本地状态,但如果底层Apollo缓存里还留着旧数据,列表查询会覆盖React-Admin的本地状态,导致记录“复活”。


解决方案

方案1:删除后手动更新Apollo缓存

修改deleteRecord函数,在mutation成功后,用Apollo的cache.evict和writeQuery方法移除缓存中的记录,同时更新列表查询的缓存。

单条删除适配

假设你的列表查询叫GetPosts,数据类型的__typename是Post,根据实际情况替换:

import { gql } from '@apollo/client';

// 替换成你项目中实际的列表查询语句
const GET_POSTS = gql`
  query GetPosts($pagination: PaginationInput, $sort: SortInput, $filter: FilterInput) {
    posts(pagination: $pagination, sort: $sort, filter: $filter) {
      id
      // 其他需要的字段
    }
  }
`;

const deleteRecord = async (id) => {
  const { data } = await apolloClient.mutate({
    mutation: gql`
      mutation DeleteRecord($id: ID!) {
        deleteRecord(id: $id) {
          success
        }
      }
    `,
    variables: { id },
    update(cache) {
      // 从缓存中移除单条记录
      cache.evict({ id: cache.identify({ __typename: 'Post', id }) });
      
      // 更新列表缓存,移除已删除的记录
      try {
        // 读取当前列表的缓存数据
        const existingPosts = cache.readQuery({ query: GET_POSTS });
        if (existingPosts) {
          cache.writeQuery({
            query: GET_POSTS,
            data: {
              posts: existingPosts.posts.filter(post => post.id !== id)
            }
          });
        }
      } catch (err) {
        // 如果缓存里没有该列表的查询结果,忽略错误即可
      }
    }
  });
  return { data };
};

批量删除适配

批量删除时不需要额外修改deleteMany方法,上面的deleteRecord已经在单条删除时处理了缓存更新,批量调用时会自动逐个清理缓存中的对应记录。

方案2:禁用列表查询的缓存(临时方案)

如果不想手动维护缓存,可以给列表查询加上fetchPolicy: 'network-only',强制每次都从远程拉取最新数据。但这会增加网络请求次数,影响性能,仅适合临时测试:

// 在执行列表查询的代码中添加fetchPolicy
apolloClient.query({
  query: GET_POSTS,
  variables: { /* 你的分页、排序、过滤参数 */ },
  fetchPolicy: 'network-only'
});

注意事项

  • 务必把代码里的__typename(比如Post)和查询名称(比如GetPosts)替换成你项目中实际使用的内容
  • 如果列表查询带有动态参数(如分页页码、过滤条件),调用cache.readQuery时要传入对应的变量,才能正确读取缓存的列表数据
  • 你当前的delete和deleteMany方法返回格式完全符合React-Admin的要求,无需修改这部分逻辑

内容的提问来源于stack exchange,提问作者Simon Mulquin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 23:22:49