7

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

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

现在假设连接速度较慢的用户创建了一个项目。在这种情况下,我会触发一个创建项目突变并乐观地更新我的 UI。这很好用。到目前为止没问题

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

  1. UI 应立即更新为新名称
  2. 新名称最终应保留在服务器中

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

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

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

4

2 回答 2

5

如果您有权访问服务器,则可以实现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来减少用户键入时的请求数。

于 2018-11-13T09:26:13.673 回答
2

我认为实现所需效果的最简单方法是实际放弃乐观更新,转而自己管理组件状态。我现在没有足够的能力写出一个完整的例子,但是你的基本组件结构应该是这样的:

<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 } })
  }
}

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

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

这也意味着如果您只想使用此表单进行编辑,需要从缓存中获取数据,然后使用它来填充您的初始状态(即this.state.created在上面的示例中)。您可以使用该Query组件,只需确保在组件提供的道具Form之前不渲染实际组件。dataQuery

于 2018-11-16T18:16:49.110 回答