2

我的流星/反应/阿波罗(带提升)项目有问题。当我从服务器查询数据时,它会将 __typename 添加到查询中的每个对象和子对象中,但在我的情况下,它会产生一个主要问题,因为我通常会重用这些数据以将它们发送到其他突变。现在另一个突变告诉我有一个错误,因为 __typename 字段未在我的 graphql 模式中定义。

我试图通过将 addTypename: false 字段添加到我的 apollo 客户端来修复,但它没有改变任何东西(注意我正在使用 apollo boost,这可能是它无法正常工作的原因):

const client = new ApolloClient({
    uri: Meteor.absoluteUrl('graphql'),
    addTypename: false,
    request: operation =>
        operation.setContext(() => ({
            headers: {
                authorization: Accounts._storedLoginToken()
            }
        }))
})

此外,即使它有效,它似乎也不是很优化。在我看来,在查询结果中添加了一个字段,我很惊讶没有在网上找到任何明确的解决方案。一些建议的解决方案:

  • 在客户端手动过滤
  • 将中间件添加到 apollo
  • 将 __typename 字段添加到我的所有模式中......

但它们似乎都不适合阿波罗计划带来的“简单”查询。我希望提供一个更简单、更合乎逻辑的解决方案,但到目前为止,找不到任何解决方案。

4

3 回答 3

5

即使 usingapollo-client和 not apollo-boost,您也不应该设置addTypename为 false ,除非您有令人信服的理由这样做。该__typename字段用于InMemoryCache规范化查询结果,因此省略它可能会导致缓存出现意外行为。

不幸的是,这个问题没有“灵丹妙药”。请求查询然后将该查询的数据用作其他查询的变量可能被解释为滥用 API。Type查询返回的值和用作Input Type参数的值是完全不同的东西,即使它们作为 Javascript 对象共享一个或多个字段。就像您不能在模式中互换使用类型和输入类型一样,不应该期望它们可以在客户端互换使用。

这也意味着,如果您发现自己处于这种情况,您可能需要重新审视一下您的架构设计。毕竟,如果数据已经存在于服务器上,传递它的 id 并在服务器端检索它就足够了,而不必传递整个对象。

如果您使用一些查询来填充一个或多个输入,然后在突变中使用这些输入的值,那么您可能已经将初始查询数据转换为组件状态,然后在您的突变中使用它。在这种情况下,__typename或任何其他不可编辑的字段可能首先不应该作为组件状态的一部分包含在内。

归根结底,进行此类操作有望成为例外,而不是规则。我会创建某种辅助函数来“清理”您的输入并继续前进。

function stripTypenames (value) {
    if (Array.isArray(value)) {
        return value.map(stripTypenames)
    } else if (value !== null && typeof(value) === "object") {
      const newObject = {}
      for (const property in value) {
          if (property !== '__typename') {
            newObject[property] = stripTypenames(value[property])
          }
      }
      return newObject
    } else {
      return value
    }
}
于 2018-10-18T12:51:26.660 回答
0

这里。'__typename' 可以使用以下辅助函数删除

const cleanedObject = omitDeep(myObject, "__typename")

const omitDeep = (obj, key) => {
    const keys = Object.keys(obj);
    const newObj = {};
    keys.forEach((i) => {
      if (i !== key) {
        const val = obj[i];
        if (val instanceof Date) newObj[i] = val;
        else if (Array.isArray(val)) newObj[i] = omitDeepArrayWalk(val, key);
        else if (typeof val === 'object' && val !== null) newObj[i] = omitDeep(val, key);
        else newObj[i] = val;
      }
    });
    return newObj;
  };

const omitDeepArrayWalk = (arr, key) => {
  return arr.map((val) => {
    if (Array.isArray(val)) return omitDeepArrayWalk(val, key)
    else if (typeof val === 'object') return omitDeep(val, key)
    return val
  })
}
于 2019-02-16T04:38:49.057 回答
0

您不应该删除 __typename。它们用于缓存,也用于联合类型。可能应该等待阿波罗的更新。不幸的是我现在也有问题,我找不到合适的解决方案。首先,我曾经简单地删除所有类型名称,但现在我遇到了联合类型的问题。

于 2020-10-29T08:49:25.220 回答