在 Relay 中,node interface 和 global ID spec 起什么作用?

In Relay, what role do the node interface and the global ID spec play?

我从 relay-starter-kit 开始,还通过 Relay 和 GraphQL 文档开始了我的工作。但也有相当多的地方是无法解释和神秘的。

说真的,我到处阅读了很多关于所有这些事情的文档,但找不到对以下问题的任何令人满意的解释:

这是做什么用的?我输入了日志记录,但它根本就没有被调用过:

var {nodeInterface, nodeField} = nodeDefinitions(
  (globalId) => {
    var {type, id} = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    } else if (type === 'Widget') {
      return getWidget(id);
    } else {
      return null;
    }
  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    } else if (obj instanceof Widget) {
      return widgetType;
    } else {
      return null;
    }
  }
);

而这个的实际效果是什么:

interfaces: [nodeInterface],

可能与此有关,这里的 node 字段是做什么的:

var queryType = new GraphQLObjectType({
  name: 'Query',
  fields: () => ({
    node: nodeField,
    // Add your own root fields here
    viewer: {
      type: userType,
      resolve: () => getViewer(),
    },
  }),
});

id 字段的魔力是什么? globalIdField 有什么用?

我的数据库中有一个 id,我想我可以在我的 GraphQL 对象中使用它:

而不是:

id: globalIdField('User'),

我想使用我的数据库id:

id: {
  type: GraphQLID,
  description: 'The identifier'
},

但如果我这样做,我会在浏览器中收到一条错误消息,提示 RelayQueryWriter: Could not find a type name for record '1'

我可以通过将 __typename 添加到我的组件容器中继查询来消除该错误,但这似乎完全错误。

如果你能在这里给出更深入的内部和更好的解释并完善官方文档,那就太好了。

谢谢

当 Relay 需要 refetch 对象时,Node 根字段与全局唯一 ID 结合使用。当您调用 this.props.relay.forceFetch() 或将字段添加到全局 ID 已知的对象的查询中时,会发生重新提取,因为它已被部分提取。

在这种情况下,中继将缩短常规查询并直接使用其全局 ID 和 node 根调用执行对象查询。

示例:

假设首次解析此查询时 $showCommentsfalse

query {
  viewer {
    stories(first: 10) {
      edges {
        node {
          id,
          comments(first: 10) @include(if: $showComments) { 
            author, 
            commentText 
          }
          text,
        }
      }
    }
  }
}

这将导致提取 idtext 一些故事,其 ID 现在已知。

想象一下,在未来的某个时间,变量 $showComments 变成了 true。中继将使用 node 根字段仅重新获取它需要的数据。

query {
  node(id: "ABC123") { 
    fragment on Story { comments(first: 10) { author, commentText } }
  }
  node(id: "DEF456") { 
    fragment on Story { comments(first: 10) { author, commentText } }
  }
  node(id: "GHI789") { 
    fragment on Story { comments(first: 10) { author, commentText } }
  }
  ...
}

这要看几块:

  1. 每个对象必须有一个全局唯一的 ID,或者由 type/ID 对标识(globalIdField 助手执行此操作并生成 base64 编码的字符串)。
  2. 服务器必须知道如何从全局唯一 ID 解析对象,反之亦然。这就是 nodeDefinitions 的用途。
  3. 任何希望使用此系统可重新获取的对象都必须实现 nodeInterface.

另请参阅:https://relay.dev/docs/guides/graphql-server-specification/#object-identification