我对中继和 graphql 解析方法感到困惑
I have confusion on relay and graphql resolve method
如果这是一个愚蠢的问题,我们深表歉意。这是让我感到困惑的 relay/graphql 分页代码:
const GraphQLTodo = new GraphQLObjectType({
name: 'Todo',
fields: {
id: globalIdField('Todo'),
text: {
type: GraphQLString,
resolve: (obj) => obj.text,
},
complete: {
type: GraphQLBoolean,
resolve: (obj) => obj.complete,
},
},
interfaces: [nodeInterface],
});
/* When pagination is needed, make a connection */
const {
connectionType: TodosConnection,
edgeType: GraphQLTodoEdge,
} = connectionDefinitions({
name: 'Todo',
nodeType: GraphQLTodo,
});
const GraphQLUser = new GraphQLObjectType({
name: 'User',
fields: {
id: globalIdField('User'),
todos: {
type: TodosConnection,
args: {
status: {
type: GraphQLString,
defaultValue: 'any',
},
...connectionArgs,
},
resolve: (obj, {status, ...args}) =>
connectionFromArray(getTodos(status), args),
},
totalCount: {
type: GraphQLInt,
resolve: () => getTodos().length,
},
completedCount: {
type: GraphQLInt,
resolve: () => getTodos('completed').length,
},
},
interfaces: [nodeInterface],
});
const Root = new GraphQLObjectType({
name: 'Root',
fields: {
viewer: {
type: GraphQLUser,
resolve: () => getViewer(),
},
node: nodeField,
},
});
可以看到在GraphQLTodo字段上,有text和complete字段,resolve函数传递了一个obj参数,obj是怎么传递过来的?是从 GraphQLUser 解析的吗?我已经阅读了源文档(在本例中为 obj)- 从父类型的字段解析的对象。不是来自根查询吗?这里的obj是怎么创建的?
连接
这里是(部分)魔法发生的地方:
const {
connectionType: TodosConnection,
edgeType: GraphQLTodoEdge,
} = connectionDefinitions({
name: 'Todo',
nodeType: GraphQLTodo,
});
您现在已经告诉 GraphQL TodosConnection
将由 GraphQLTodo
个节点组成。现在,让我们看一下在 GraphQLUser
对象中为连接实际获取对象的位置,它在 todos
字段上:
todos: {
type: TodosConnection,
args: {
status: {
type: GraphQLString,
defaultValue: 'any',
},
...connectionArgs,
},
resolve: (obj, {status, ...args}) =>
connectionFromArray(getTodos(status), args),
},
那么对象是从哪里来的呢?这里的关键部分是 getTodos
函数,它负责实际从数据源中获取对象数组。由于这个字段是 TodosConnection
并且我们已经在连接定义中指定节点是 GraphQLTodo
s,GraphQL 知道 text
和 complete
字段由在已返回的对象上获取(在本例中)同名字段。换句话说,返回的对象被传递给每个字段的 resolve
方法。
查询根
您在 Root
上公开了两个字段:viewer
和 node
。暂时忽略 node
,您只有一种方法可以实际查询待办事项。由于 viewer
属于 GraphQLUser
类型,并且 GraphQLUser
具有 todos
字段,因此只能将它们作为 viewer
的子字段来获取,如下所示:
{
viewer {
todos(first: 10) {
edges {
# each node is a Todo item
node {
text
complete
}
}
}
}
}
节点之谜
但是 node
字段呢? Relay 希望能够使用顶级查询获取任何对象,即在您的 Root
字段上,当给定一个唯一的 globalId
时,它只是类型名称和 ID 的 base64 编码,所以 Todo:1
被编码为 VG9kbzox
。这是在 nodeDefinitions
中设置的(您未在此处包含,但可能包含)。在这些定义中,globalId
被解析回 type
(Todo
) 和 id
(1
),然后您再次告诉它如何从数据源中获取正确的对象。它可能看起来像:
const { nodeInterface, nodeField } = nodeDefinitions(
(globalId) => {
const { type, id } = fromGlobalId(globalId);
if (type === 'Todo') {
return getTodo(id)
} else if (type === 'User') {
return getUser(id)
}
...
因为您在 GraphQLTodo
和 GraphQLUser
类型中都实现了 nodeInterface
,Relay 将能够从 Root
中查询它们中的任何一个node
字段。
如果这是一个愚蠢的问题,我们深表歉意。这是让我感到困惑的 relay/graphql 分页代码:
const GraphQLTodo = new GraphQLObjectType({
name: 'Todo',
fields: {
id: globalIdField('Todo'),
text: {
type: GraphQLString,
resolve: (obj) => obj.text,
},
complete: {
type: GraphQLBoolean,
resolve: (obj) => obj.complete,
},
},
interfaces: [nodeInterface],
});
/* When pagination is needed, make a connection */
const {
connectionType: TodosConnection,
edgeType: GraphQLTodoEdge,
} = connectionDefinitions({
name: 'Todo',
nodeType: GraphQLTodo,
});
const GraphQLUser = new GraphQLObjectType({
name: 'User',
fields: {
id: globalIdField('User'),
todos: {
type: TodosConnection,
args: {
status: {
type: GraphQLString,
defaultValue: 'any',
},
...connectionArgs,
},
resolve: (obj, {status, ...args}) =>
connectionFromArray(getTodos(status), args),
},
totalCount: {
type: GraphQLInt,
resolve: () => getTodos().length,
},
completedCount: {
type: GraphQLInt,
resolve: () => getTodos('completed').length,
},
},
interfaces: [nodeInterface],
});
const Root = new GraphQLObjectType({
name: 'Root',
fields: {
viewer: {
type: GraphQLUser,
resolve: () => getViewer(),
},
node: nodeField,
},
});
可以看到在GraphQLTodo字段上,有text和complete字段,resolve函数传递了一个obj参数,obj是怎么传递过来的?是从 GraphQLUser 解析的吗?我已经阅读了源文档(在本例中为 obj)- 从父类型的字段解析的对象。不是来自根查询吗?这里的obj是怎么创建的?
连接
这里是(部分)魔法发生的地方:
const {
connectionType: TodosConnection,
edgeType: GraphQLTodoEdge,
} = connectionDefinitions({
name: 'Todo',
nodeType: GraphQLTodo,
});
您现在已经告诉 GraphQL TodosConnection
将由 GraphQLTodo
个节点组成。现在,让我们看一下在 GraphQLUser
对象中为连接实际获取对象的位置,它在 todos
字段上:
todos: {
type: TodosConnection,
args: {
status: {
type: GraphQLString,
defaultValue: 'any',
},
...connectionArgs,
},
resolve: (obj, {status, ...args}) =>
connectionFromArray(getTodos(status), args),
},
那么对象是从哪里来的呢?这里的关键部分是 getTodos
函数,它负责实际从数据源中获取对象数组。由于这个字段是 TodosConnection
并且我们已经在连接定义中指定节点是 GraphQLTodo
s,GraphQL 知道 text
和 complete
字段由在已返回的对象上获取(在本例中)同名字段。换句话说,返回的对象被传递给每个字段的 resolve
方法。
查询根
您在 Root
上公开了两个字段:viewer
和 node
。暂时忽略 node
,您只有一种方法可以实际查询待办事项。由于 viewer
属于 GraphQLUser
类型,并且 GraphQLUser
具有 todos
字段,因此只能将它们作为 viewer
的子字段来获取,如下所示:
{
viewer {
todos(first: 10) {
edges {
# each node is a Todo item
node {
text
complete
}
}
}
}
}
节点之谜
但是 node
字段呢? Relay 希望能够使用顶级查询获取任何对象,即在您的 Root
字段上,当给定一个唯一的 globalId
时,它只是类型名称和 ID 的 base64 编码,所以 Todo:1
被编码为 VG9kbzox
。这是在 nodeDefinitions
中设置的(您未在此处包含,但可能包含)。在这些定义中,globalId
被解析回 type
(Todo
) 和 id
(1
),然后您再次告诉它如何从数据源中获取正确的对象。它可能看起来像:
const { nodeInterface, nodeField } = nodeDefinitions(
(globalId) => {
const { type, id } = fromGlobalId(globalId);
if (type === 'Todo') {
return getTodo(id)
} else if (type === 'User') {
return getUser(id)
}
...
因为您在 GraphQLTodo
和 GraphQLUser
类型中都实现了 nodeInterface
,Relay 将能够从 Root
中查询它们中的任何一个node
字段。