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

React/Apollo应用数据异常:Network数据正确但Apollo返回错误

React/Apollo 应用缓存导致数据混乱问题解决

我开发的React/Apollo应用出现数据异常:Chrome网络面板显示接口原始返回数据正确,但Apollo返回的数据却出现错误。

预期与实际数据对比

预期返回格式

{
  id: 12345,
  name: 'some record',
  status: { id: 1, name: 'Active' },
  types: [
    { id: 1, name: 'Client' },
    { id: 4, name: 'Example' }
  ],
  // ... 更多属性
}

实际Apollo返回格式

{
  id: 12345,
  name: 'some record',
  status: { id: 1, name: 'Client' }, // ← 此处"Active"被错误替换为"Client"
  types: [
    { id: 1, name: 'Client' },
    { id: 4, name: 'Example' }
  ],
  // ... 更多属性
}

问题原因

Apollo缓存默认使用id字段作为实体的唯一标识,当不同类型的实体(如Status和Type)ID相同时,缓存会错误地将它们视为同一个实体,导致数据覆盖。

解决办法

1. 单个查询禁用缓存(临时方案)

在useQuery的配置中添加fetchPolicy: 'no-cache',让该查询跳过缓存,直接使用网络返回的数据:

const { data, refetch } = useQuery(gql`...`, {
  variables: {...},
  fetchPolicy: 'no-cache'
});

也可以使用fetchPolicy: 'network-only',强制每次从网络获取数据,但仍会将结果写入缓存。

2. 为实体添加唯一缓存键(推荐方案)

通过配置Apollo Client的dataIdFromObject,使用__typename + id作为缓存的唯一标识,区分不同类型的实体:

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: '/graphql',
  cache: new InMemoryCache({
    dataIdFromObject: (object) => {
      if (object.__typename && object.id) {
        // 用类型名+ID生成唯一缓存键
        return `${object.__typename}:${object.id}`;
      }
      return null; // 其他情况由Apollo自动处理
    }
  })
});

大部分GraphQL服务会自动为返回的实体添加__typename字段,确保不同类型的同ID实体不会被缓存混淆。

3. 全局禁用缓存(不推荐)

如果完全不需要缓存功能,可以全局配置Apollo Client禁用缓存,但这会影响应用性能,仅作为极端情况使用:

const client = new ApolloClient({
  uri: '/graphql',
  cache: new InMemoryCache({ addTypename: false }),
  defaultOptions: {
    query: {
      fetchPolicy: 'no-cache',
    },
  },
});

我的查询代码

const { data, refetch } = useQuery(gql`
    query GetScoreAudit(
      $page: Int, $pageSize: Int, $search: String,
      $orderBy: String, $order: Order,
      $status: Int, $type: Int
    ) {
      scoreAudit(
        page: $page, pageSize: $pageSize, search: $search,
        orderBy: $orderBy, order: $order,
        status: $status, type: $type
      ) {
        total
        nodes {
          id
          name
          managedWorkstations
          managedServers
          firewall
          wpsCompliance
          maxWpsCompliance
          mrr
          tpe
          status {
            id
            name
          }
          types {
            id
            name
          }
          serviceCompanies {
            service
            exists
          }
        }
      }
    }
  `, {
    variables: {
      page: tableOpts.pagination.page,
      pageSize: tableOpts.pagination.pageSize,
      search: tableOpts.filters.search,
      orderBy: tableOpts.orderBy,
      order: tableOpts.order,
      status: tableOpts.filters.status,
      type: tableOpts.filters.type
    }
  });

  console.log(data);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 13:10:20