什么类型的 Relay mutator 配置适合插入新记录?
Posted
技术标签:
【中文标题】什么类型的 Relay mutator 配置适合插入新记录?【英文标题】:What type of Relay mutator configuration is appropriate for inserting a new record? 【发布时间】:2016-04-03 23:43:21 【问题描述】:我正在深入研究 GraphQL 和 Relay。到目前为止,对我来说,一切都比较顺利和容易理解。我有一个与 Accounts
和 Teams
一起使用的 GraphQL 模式。两者之间还没有任何关系。我对帐户和团队的连接进行了一些特定于 Relay 的 GraphQL 调整。这是这两个连接的示例查询...
viewer
teams
edges
node
id,
name
accounts
edges
node
id,
username
我已经准备好创建一个新帐户的 GraphQL 突变。这是 GraphQL 的表示形式...
type Mutation
newAccount(input: NewAccountInput!): NewAccountPayload
input NewAccountInput
username: String!
password: String!
clientMutationId: String!
type NewAccountPayload
account: Account
clientMutationId: String!
type Account implements Node
id: ID!
username: String!
date_created: String!
我现在正在尝试创建使用此 GraphQL 突变的客户端 Relay 突变。不过,我对如何正确执行此操作感到非常困惑。我已经按照示例进行了操作,但我想出的任何东西似乎都无法正常运行。我往往会遇到与片段组合有关的错误。
如果我正在编写一个使用此 GraphQL 突变的 Relay 突变,那么合适的突变器配置应该是什么?我应该使用RANGE_ADD
吗?
【问题讨论】:
【参考方案1】:对于您的客户端突变,您可以使用以下内容:
export default class AddAccountMutation extends Relay.Mutation
static fragments =
viewer: () => Relay.QL`
fragment on Viewer
id,
`,
;
getMutation()
return Relay.QL`mutationaddAccount`;
getVariables()
return
newAccount: this.props.newAccount,
;
getFatQuery()
return Relay.QL`
fragment on AddAccountPayload
accountEdge,
viewer
accounts,
,
`;
getConfigs()
return [
type: 'RANGE_ADD',
parentName: 'viewer',
parentID: this.props.viewer.id,
connectionName: 'accounts',
edgeName: 'accountEdge',
rangeBehaviors:
'': 'append',
,
];
getOptimisticResponse()
return
accountEdge:
node:
userName: this.props.newAccount.userName,
,
,
viewer:
id: this.props.viewer.id,
,
;
然后,在您的 GraphQL 架构中,您需要返回新创建的边以及光标:
var GraphQLAddAccountMutation = mutationWithClientMutationId(
name: 'AddAccount',
inputFields:
newAccount: type: new GraphQLNonNull(NewAccountInput)
,
outputFields:
accountEdge:
type: GraphQLAccountEdge,
resolve: async (localAccountId) =>
var account = await getAccountById(localAccountId);
var accounts = await getAccounts();
return
cursor: cursorForObjectInConnection(accounts, account)
node: account,
;
,
viewer:
type: GraphQLViewer,
resolve: () => getViewer()
,
,
mutateAndGetPayload: async ( newAccount ) =>
var localAccountId = await createAccount(newAccount);
return localAccountId;
);
var
connectionType: AccountsConnection,
edgeType: GraphQLAccountEdge,
= connectionDefinitions(
name: 'Account',
nodeType: Account,
);
您需要将 getAccounts()、getAccountById() 和 createAccount 方法调用替换为您的服务器/后端使用的任何方法。
可能有更好的方法来计算光标,而无需执行多次服务器行程,但请记住中继助手 cursorForObjectInConnection 不会对对象进行任何类型的深度比较,因此如果您需要通过以下方式查找帐户列表中的 id,您可能需要进行自定义比较:
function getCursor(dataList, item)
for (const i of dataList)
if (i._id.toString() === item._id.toString())
let cursor = cursorForObjectInConnection(dataList, i);
return cursor;
最后,将 GraphQL 突变作为“addAccount”添加到您的架构突变字段中,该字段由客户端突变引用。
【讨论】:
几个问题,因为这看起来与我在自己的代码中所做的非常接近... 1. 为什么在输出字段中提供viewer
字段?你怎么知道要这样做? 2. 在您的突变片段中,为什么片段似乎与viewer
模式不匹配,我假设它包含一些连接,例如query viewer accounts edges node id, username, ...
?我在你的胖查询中看到了这个结构。
关于您的问题: 1. 我认为查看器应该包含在输出字段中(并因此通过胖查询返回给客户端的原因是查看器包含帐户列表,并且因此应该在插入新节点后获取。FB 在他们的 ToDo App 示例中包含此内容(在 AddTodoMutation 中)。2.片段应包含突变本身所需的任何字段,例如 getOptimisticResponse。因为帐户是从服务器通过胖查询,我们真的不需要在片段模式中指定“帐户”。【参考方案2】:
现在,我正在按照大约 5 个步骤来定义突变:
-
根据您所定位的图表部分定义输入变量 - 在您的情况下,它是一个新帐户,因此您只需要新数据
根据 #1 命名突变 - 对你来说,那就是
AddAccountMutation
根据受突变影响的内容定义胖查询 - 对您而言,这只是 viewer
上的 accounts
连接,但我相信您的架构将来会变得更加复杂
根据如何将胖查询与本地图相交来定义突变配置
定义您需要满足#1、#3 和#4 要求的突变片段
一般来说,第 4 步是人们最困惑的一步。那是因为它令人困惑。很难在 Stack Overflow 的回答中总结为什么我觉得这是个好建议,但是……我建议您使用 FIELDS_CHANGE
来处理所有突变*。这相对容易解释和推理 - 只需告诉 Relay 如何查找与突变有效负载中的***字段相对应的节点。然后,Relay 将使用突变配置来构建一个“跟踪查询”,代表您到目前为止所请求的所有内容,并将其与代表所有可能更改的“胖查询”相交。在您的情况下,您希望相交查询类似于viewer accounts(first: 10) edges nodes ...
,这意味着您需要确保您已经在某处请求了现有帐户。但是你几乎肯定有,如果你没有……也许你实际上不需要在本地为这个突变做任何改变!
有意义吗?
编辑:为了清楚起见,这就是我对胖查询和配置的意思。
getConfigs()
return [
type: "FIELDS_CHANGE",
fieldIDs:
viewer: this.props.viewer.id
]
getFatQuery()
return Relay.QL`
fragment on AddAccountMutation
viewer
accounts
`
*附录:我目前认为只有一两个理由不使用FIELDS_CHANGE
。首先是您无法可靠地说明哪些字段正在发生变化,因此您只想直接操作图表。第二个是因为您决定需要FIELDS_CHANGE
的更具体变体(如NODE_DELETE
、RANGE_ADD
等)提供的查询性能优化。
【讨论】:
以上是关于什么类型的 Relay mutator 配置适合插入新记录?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Relay Mutation 的结果作为 Relay Container Prop
如何在服务器端的 Relay Mutations 中实现对另一个模型的引用?
错误:“突变”类型上的未知字段“讨论”。使用 Relay 和 React `useMutation` 钩子