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

React Native中使用Apollo-React调用GraphQL Union报错求助

解决React Native + Apollo GraphQL处理Union类型的"Requested keys of a value that is not an object"错误

我之前也碰到过几乎一模一样的问题!结合你给出的场景和代码,这个错误大概率是React Native环境下Apollo Cache处理Union类型时的序列化/反序列化差异导致的——毕竟关闭远程调试时RN用的是Hermes或JSC引擎,和Chrome的V8(远程调试依赖的引擎)行为不一样,再加上服务端的__typename返回可能有遗漏,就触发了这个报错。

下面是我亲测有效的解决方案,按优先级尝试:

1. 先确认服务端返回的__typename字段是否存在

这是最常见的根源!Apollo识别Union类型完全依赖返回数据里的__typename字段,而有些服务端框架(比如你用的Youshido bundle)默认不会自动添加这个字段。

  • 关闭远程调试,用Charles抓包或者RN的Network Inspector查看实际返回的JSON,比如questions数组里的每个元素是否带有__typename:
    "questions": [
      {
        "__typename": "QuestionUnionTypeA",
        "id": "1",
        "parameterA": "test"
      }
    ]
    
  • 如果没有这个字段,需要在服务端配置开启自动添加__typename,或者在你的GraphQL查询里手动请求它(虽然Apollo应该会自动注入,但保险起见可以加上):
    const FindForm = gql`query FindForm($id: ID!){
      findForm(id: $id){
        id
        title
        questions {
          id
          __typename  # 手动添加
          ... on QuestionUnionTypeA { parameterA }
          ... on QuestionUnionTypeB { parameterB }
          ... on QuestionUnionTypeC { parameterC }
        }
      }
    }`;
    

2. 用Apollo CLI自动生成Fragment Matcher配置

你手动写的Fragment Matcher可能存在拼写错误或者遗漏,用官方工具生成更可靠:

  1. 安装Apollo CLI:
    npm install -g apollo
    
  2. 下载服务端的Schema:
    apollo client:download-schema --endpoint=http://10.1.68.64:8000/graphql schema.json
    
  3. 生成Fragment Matcher的配置文件:
    apollo client:codegen --localSchemaFile=schema.json --target=javascript --outputFlat src/fragmentTypes.js
    
  4. 替换你手动写的Fragment Matcher:
    import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
    import introspectionResult from './fragmentTypes';
    
    const fragmentMatcher = new IntrospectionFragmentMatcher({
      introspectionQueryResultData: introspectionResult
    });
    

3. 调整InMemoryCache的ID生成逻辑

React Native的引擎在处理缓存对象时,对无唯一标识的Union类型可能会有序列化问题,添加dataIdFromObject确保每个类型都有唯一ID:

import { InMemoryCache, defaultDataIdFromObject } from 'apollo-cache-inmemory';

const cache = new InMemoryCache({
  fragmentMatcher,
  dataIdFromObject: (obj) => {
    // 给每个Union类型实例生成唯一ID
    switch(obj.__typename) {
      case 'QuestionUnionTypeA': return `QuestionA:${obj.id}`;
      case 'QuestionUnionTypeB': return `QuestionB:${obj.id}`;
      case 'QuestionUnionTypeC': return `QuestionC:${obj.id}`;
      default: return defaultDataIdFromObject(obj); // 其他类型用默认逻辑
    }
  }
});

4. 临时跳过缓存验证问题

如果上面的方法还没解决,试试在查询里禁用缓存,确认是不是缓存处理的问题:

const query = graphql(FindForm, {
  options: {
    variables: { id: this.state.id },
    fetchPolicy: 'network-only' // 直接请求网络,不使用缓存
  }
})(resultDisplayer);

如果这样不报错,就可以确定是缓存配置的问题,回到前面的步骤调整。

为什么远程调试时正常?

远程调试时,RN的JS代码跑在Chrome的V8引擎里,而本地运行时用的是Hermes或JSC,这两个引擎在JSON序列化、对象处理上有细微差异——V8可能对缺失__typename或者缓存对象的不规范结构更宽容,而Hermes/JSC会严格校验,从而抛出错误。

内容的提问来源于stack exchange,提问作者R.Duteil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:05:12