A graphic with the words “Loaders” -> “Component” -> “Action” connected by arrows and depicted cyclically.
2022年6月22日

Remix 中的数据流

Jim Nielsen
设计总监

当 React 首次出现时,其最引人注目的功能之一就是其“单向数据流”。这仍然在 React 文档的 “React 思维” 页面中概述。

层次结构顶部的组件将把您的数据模型作为 prop 获取。如果您更改了底层数据模型并再次调用 root.render(),则 UI 将更新。您可以看到 UI 如何更新以及在哪里进行更改。React 的单向数据流(也称为单向绑定)使一切都保持模块化和快速。

其理念是数据只能单向流经您的应用程序,因此使您的应用程序更易于直观理解、理解和推理。

Illustration of the idea of one-way data flow depicting lines drawing a circular flow from view to action to state.

这总结为一句话:“UI 是状态的函数”,或 ui = fn(state)。每当由于某个操作导致某些状态发生变化时,视图都会重新渲染。迄今为止,已经创建了许多复杂的“状态管理”解决方案来促进使用这种思维模型构建应用程序。

然而,这里很少有人承认的问题是,这种“单向数据流”有点用词不当。它实际上是客户端上的单向数据流。但是,让数据完全存在于客户端通常是不切实际的。大多数时候,您需要持久化数据——同步它——这意味着您需要数据双向流动:在客户端和服务器之间。

Illustration of the flow “View -> Action -> State” framed in a browser on the left. On the right is an illustartion of a server with a database. Two arrows connect these two illustrations denoting network transfer.

许多状态管理工具只能帮助您管理客户端上的状态,但它们无法帮助您有效地跨越网络鸿沟:客户端状态和服务器状态之间的差距。

Illustration of the flow “View -> Action -> State” framed in a browser on the left. On the right is an illustartion of a server with a database. Two arrows connect these two illustrations denoting network transfer. The visual emphasis is on the network part of the graphic with “?”s surrounding it.

进入 Remix:“Remix 的主要功能之一是简化与服务器的交互,以将数据获取到组件中。”Remix 扩展了跨网络的数据流,使其真正成为单向和循环的:从服务器(状态)到客户端(视图),再回到服务器(操作)。

Illustration of the flow “View -> Action -> State” crossing between the browser and the server.

当有人说您的“UI 是状态的函数”时,一种更细致的方式来解开该语句中的假设是:UI 是远程状态本地状态的函数。在传统的 React 应用程序中,所有状态都存在于客户端,您想要持久化的部分必须跳出“单向数据流”并跨网络与服务器同步。您可以想象,这是一个容易出现错误的区域。

然而,在 Remix 中,“UI 作为状态的函数”的概念发生了转变,因为远程状态可以更容易地与本地状态分离。“有什么区别?”您可能会问。可以这样理解。

远程状态是任何需要持久化的数据,例如用户数据。此状态(例如,用户有多少未读通知?)存储在客户端之外,并通过 Remix 机制(如 加载器操作)与您的应用程序协调。

(**注意:**Remix 通过还提供围绕通过 转换获取器 传输持久化数据的 stateful 信息来帮助您跨越网络鸿沟——无需通过诸如 isLoading 或诸如 initial | loading | success | failed 的枚举之类的布尔值自己跟踪每个网络请求的状态)。

相比之下,本地状态是短暂的数据,如果丢失(例如,通过刷新)不会对用户体验产生负面影响。此状态(例如,显示用户通知的下拉菜单是否打开?)通过 React 状态或本地存储等机制存储在客户端。重要的是,它不需要持久化并跨网络同步,从而降低了复杂性和潜在的错误。

Illustration depicting a one-way flow of “remote data” between the client/server facilitated by remix. A one-way flow of “local data” is on the client exclusively facilitated by React and/or localStorage.

表单、获取器、加载器、操作,这些都是 Remix 中的“状态管理”解决方案(尽管我们不这样称呼它们)。它们为您提供了保持客户端和服务器之间持久化状态同步的工具,确保数据以单向循环方式流经您的应用程序和网络:从加载器到组件,再到操作,然后返回。

The words “Loader” -> “Action” -> “Component” shown in a circular diagram.

使用 Remix,您的 UI 成为跨网络的状态函数,而不仅仅是本地状态函数。关于 Remix 的数据抽象的一个有趣的类比是 React 的虚拟 DOM 抽象。

在 React 中,您不必担心自己更新 DOM。您设置状态,虚拟 DOM 会执行所有差异以找出如何对 DOM 进行有效的更新。Remix 将此理念扩展到持久化数据的 API 层。

在 Remix 中,您不必担心将客户端状态与服务器同步。您可以使用变异“设置状态”,加载器会接管以重新获取最新数据并更新组件视图。

Screenshot of code example in Remix illustrating the one-way, cyclical flow of data through an app. There’s a loader function whose code flows into the Route component whose code, via a <Form> flows into the action function whose code flows back into a loader again.

希望这有助于说明 Remix 如何极大地帮助减少构建更好网站所需的复杂性。正如 Kent 在他在 RenderATL 的演讲中所说,因为 Remix 在 JavaScript 之前工作,这对您的用户来说是一个优势,因为他们获得了渐进增强支持的体验。但对于您作为开发人员来说,这也是一个优势,因为您无需构建传统上与状态管理解决方案耦合的所有复杂性。

当您使用 Remix 时,您无需担心应用程序状态管理。Redux、Apollo,尽管这些工具很酷,但当您使用 Remix 时,您不需要它们,因为我们甚至不需要客户端 JavaScript 就能让整个系统工作……[考虑您正在构建的应用程序] 并假装您可以丢弃所有与应用程序状态管理相关的代码……这就是使用 Remix 的感觉。如果它可以在浏览器中无需 JavaScript 运行,则意味着您不需要浏览器中任何需要状态管理的内容。


获取有关最新 Remix 新闻的更新

抢先了解新的 Remix 功能、社区活动和教程。