【问题标题】:Apollo client: Making optimistic updates while creation is still in progressApollo 客户端:在创建过程中进行乐观更新
【发布时间】:2019-04-10 08:56:15
【问题描述】:

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

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

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

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

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

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

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

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

【问题讨论】:

  • 在创建的情况下进行乐观更新。如果有更新,请保持突变准备就绪,并在创建操作完成并且您拥有 id 后在后台执行此操作

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


【解决方案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 来减少用户键入时的请求数。

【讨论】:

    【解决方案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 组件,只要确保在获得 Query 组件提供的 data 属性之前不渲染实际的 Form 组件。

    【讨论】:

      猜你喜欢
      • 2018-08-17
      • 2017-04-02
      • 2021-01-24
      • 2021-09-24
      • 2017-11-02
      • 2018-06-04
      • 2019-08-12
      • 2019-04-02
      • 2019-02-12
      相关资源
      最近更新 更多