更多关于变更和更新 Store

接下来我们将实现投票功能!经过身份验证的用户可以提交链接投票。最多投票数的链接将显示在单独的路由!

准备 React 组件

再一次我们将为需要的功能准备一个新的组件。

Link.js 文件中更新 render 函数:

.../hackernews-react-apollo/src/components/Link.js
render() {
  const userId = localStorage.getItem(GC_USER_ID)
  return (
    <div className='flex mt2 items-start'>
      <div className='flex items-center'>
        <span className='gray'>{this.props.index + 1}.</span>
        {userId && <div className='ml1 gray f11' onClick={() => this._voteForLink()}></div>}
      </div>
      <div className='ml1'>
        <div>{this.props.link.description} ({this.props.link.url})</div>
        <div className='f6 lh-copy gray'>{this.props.link.votes.length} votes | by {this.props.link.postedBy ? this.props.link.postedBy.name : 'Unknown'} {timeDifferenceForDate(this.props.link.createdAt)}</div>
      </div>
    </div>
  )
}

我们已经准备了 Link 组件来渲染每个链接的投票数以及发布它的用户的名称。此外,如果用户当前登录,将会显示 upvote 按钮。如果 LinkUser 不相关联,则用户的名称将被显示为 Unknown

请注意,我们还使用一个名为 timeDifferenceForDate 的函数,它会传递每个链接的 createdAt信息。该函数将采用时间戳并将其转换为更加用户友好的字符串,例如 “3小时前”

创建 timeDifferenceForDate 函数,以便可以在 Link 组件中导入和使用它。

最后,每个 Link 元素也将在列表中显示它的位置,所以你必须从 LinkList 组件传递一个 index

请注意,由于 votes 尚未包含在查询中,因此该应用程序将不会运行。在后面我们将实现!

更新模式

对于这个新功能,还需要重新更新模式,因为链接上的投票将使用自定义的 Vote 类型。

每个 Vote 将与创建它的 User 以及它所属的 Link 相关联。我们还得在另一端声明关联。

下面是终端的输出结果:

$ gc push
 ✔ Your schema was successfully updated. Here are the changes: 

  | (+)  A new type with the name `Vote` is created.
  |
  | (+)  The relation `UsersVotes` is created. It connects the type `User` with the type `Vote`.
  |
  | (+)  The relation `VotesOnLink` is created. It connects the type `Link` with the type `Vote`.

Your project file project.graphcool was updated. Reload it in your editor if needed.

真棒!现在更新了模式,我们可以修复之前的问题以正常运行应用程序。可以通过在 LinkList 中定义的allLinks 查询中包含有关链接投票的信息。

我们所做的事情包括有关发布链接的用户的信息以及有关链接在查询的有效载荷中的投票的信息。现在可以再次运行应用程序,链接将被正确显示。

我们现在继续实现 upvote 变更!

调用变更

现在这一步应该很熟悉。通过包裹 Link 组件和 CREATE_VOTE_MUTATION 可以使组件调用 createVoteMutation

请注意,在该方法的第一部分中,将检查当前用户是否已经为该链接投票。如果是这种情况,就不是实际执行变更。

我们现在可以去测试实现了!运行 yarn start 并点击链接上的 upvote 按钮。如果还没有获得任何 UI 反馈,刷新页面后,将看到添加的投票。

应用程序仍然存在缺陷。由于 链接 上的 投票 不会立即更新,所以 用户 目前可以提交无限期投票,直到页面刷新。只有这样,保护机制才会适用,而不是u pvote,点击投票按钮将简单地导致控制台中的以下日志记录语句:_User(cj42qfzwnugfo01955uasit8l)already voted for this link。

但至少你知道这个变更是有效的。在下一节中,我们将解决问题,并确保每次变更后缓存都会被更新!

更新缓存

关于 Apollo 的一件很酷的事情是可以手动控制缓存的内容。这是非常方便的,特别是在执行变更之后,因为这样可以准确地控制希望更新缓存的方式。在这里,我们将使用它来确保 UI 在执行 createVote 变更之后显示正确的投票数。

我们可以通过使用 Apollo 的 命令式存储 API 来实现此功能。

当服务器返回响应时,将会调用作为参数添加到变量调用中的 update 函数。它接收到变量的有效负载(data)和当前的缓存(store)作为参数。然后,可以使用此输入来确定缓存的新状态。

请注意,我们已经 解构 服务器响应并从中检索 createVote 字段。

好的,所以现在你知道这个 update 函数是什么,但实际的实现将在 Link 的父组件 LinkList 中完成。

这里发生了什么?

  1. 我们从当前状态的store 读取 ALL_LINKS_QUERY 的缓存数据。
  2. 然后检索用户刚刚从该列表中投票的链接。还通过将其 投票 重置为服务器刚刚返回的 投票 来操纵该链接。
  3. 最后,将修改后的数据写入 store。

接下来,需要将此函数传递给 Link,以便调用。

就是这样! updater 函数现在将被执行,并确保在执行变更之后存储已正确更新。store 更新将触发组件的重新渲染,从而使用正确的信息更新UI!

在我们这样做的时候,我们还实现 update 添加新的链接!

update 函数的工作原理与以前类似。首先读取 ALL_LINKS_QUERY 的结果的当前状态。然后将最新的链接插入顶部,并将查询结果写回 store。

相反,它也需要从定义的位置导出。

很好,现在随着新的链接添加,store 也会更新正确的信息。🤓

Unlock the next chapter
`graphcool push` 命令能做什么?
它将本地模式的更改上传到远程 Graphcool 项目
它将 git 存储库推送到 Graphcool,以便您可以一起管理项目和代码。
它告诉服务器将其远程方案更改推送到本地项目文件中
根本就没有 `graphcool push` 命令