Apollo客户端:在创建过程中进行乐观更新

时间:2018-11-06 22:09:33

标签: graphql apollo react-apollo apollo-client optimistic-ui

我希望能够在仍在创建对象时对其进行更新。

例如:说我有一个待办事项清单,可以在其中添加带有名称的项目。我还希望能够编辑项目名称。

现在说连接速度慢的用户创建了一个商品。在那种情况下,我会触发一个创建项目的变异并乐观地更新我的UI。效果很好。到目前为止没有问题

现在让我们说一下,由于网络速度较慢,创建商品突变要花一些时间。在那个时候,用户决定编辑他们刚刚创建的项目的名称。为了获得理想的体验:

  1. 用户界面应立即以新名称更新
  2. 新名称最终应保留在服务器中

我可以通过等待create突变完成(这样我才能获得商品ID),然后进行更新名称突变来实现#2。但这意味着我的UI的一部分将保持不变,直到创建项突变返回并且更新名称突变的乐观响应开始为止。这意味着将无法实现#1。

所以我想知道如何使用Apollo客户端同时实现#1和#2。

注意:我不想添加微调器或禁用编辑。我希望该应用即使在连接速度较慢的情况下也能保持响应速度。

2 个答案:

答案 0 :(得分:1)

如果您有权访问服务器,则可以实施upsert操作,因此可以将所有查询减少为此类查询:

mutation { upsertTodoItem( where: { key: $itemKey # some unique key generated on client } update: { listId: $listId text: $itemText } create: { key: $itemKey listId: $listId text: $itemText } ) { id key } }

因此,您将有一系列相同的突变,只是变量不同。因此,可以配置对这一突变的乐观响应。在服务器上,您需要检查带有key的项目是否已经存在,并分别创建或更新项目

另外,您可能希望使用apollo-link-debounce来减少用户输入时的请求数

答案 1 :(得分:1)

我认为,达到预期效果的最简单方法是实际删除乐观更新,以便自己管理组件状态。我目前没有足够的带宽来编写完整的示例,但是您的基本组件结构如下所示:

<ApolloConsumer>
  {(client) => (
    <Mutation mutation={CREATE_MUTATION}>
      {(create) => (
        <Mutation mutation={EDIT_MUTATION}>
          {(edit) => (
            <Form />
          )}
        </Mutation>        
      )}
    </Mutation>
  )}
</ApolloConsumer>

假设我们只处理一个字段-name。您的Form组件的初始状态为

{ name: '', created: null, updates: null }

提交后,表单将执行以下操作:

onCreate () {
  this.props.create({ variables: { name: this.state.name } })
    .then(({ data, errors }) => {
      // handle errors whichever way
      this.setState({ created: data.created })
      if (this.state.updates) {
        const id = data.created.id
        this.props.update({ variables: { ...this.state.updates, id } })
      }
    })
    .catch(errorHandler)
}

然后,编辑逻辑如下所示:

onEdit () {
  if (this.state.created) {
    const id = this.state.created.id
    this.props.update({ variables: { name: this.state.name, id } })
      .then(({ data, errors }) => {
        this.setState({ updates: null })
      })
      .catch(errorHandler)
  } else {
    this.setState({ updates: { name: this.state.name } })
  }
}

实际上,您的编辑突变要么在用户提交时立即触发(因为我们已经从我们的create突变中获得了响应)...或者用户所做的更改被保留并在创建突变完成后发送。

这是一个非常粗糙的示例,但是应该使您对如何处理这种情况有所了解。最大的缺点是组件状态可能与缓存不同步-您需要确保正确处理错误以防止这种情况。

这也意味着,如果您要使用此表单进行 just 编辑,则需要从缓存中提取数据,然后使用该数据填充初始状态(即{{1 }}。您可以为此使用this.state.created组件,只需确保没有渲染实际的Query组件,直到拥有Form组件提供的data道具为止。< / p>