双向数据绑定(Angular)与单向数据流(React/Flux)

IT技术 javascript angularjs reactjs flux reactjs-flux
2021-05-11 07:55:03

上周,我一直在试图弄明白双向数据绑定 (Angular)单向数据流 (React/Flux)的不同之处。他们说单向数据流更强大,更容易理解和遵循:它是确定性的,有助于避免副作用。但在我的新手眼里,它们看起来几乎一样:视图监听模型,模型对视图执行的操作做出react。两者都声称该模型是唯一的事实来源

谁能以可理解的方式全面解释它们的真正不同之处以及单向数据流如何更有益且更易于推理?

4个回答

Angular 的双向数据绑定

它是通过一种机制使视图和模型在任何一个更改时同步。在 Angular 中,你更新一个变量,它的变化检测机制将负责更新视图,反之亦然。有什么问题?您无法控制变更检测机制。我发现自己不得不求助于 ChangeDetectorRef.detectChanges 或 NgZone.run 来强制更新视图。

为了不深入研究 Angular 中的更改检测,您相信它会在您更改变量时更新您需要的内容,或者在 observable 解析后更改时,但您会发现您不知道它如何以及何时运行,有时它不会在变量更改后更新您的视图。毋庸置疑,有时很难找到问题发生的地点和时间。

React 的单向数据流

这意味着视图总是从模型中获取它的状态。要更新视图,需要先更新模型,然后再重新绘制视图。React 使视图重绘过程非常高效,因为它比较的不是实际的 DOM,而是它保存在内存中的虚拟 DOM。但是变化检测在这种动态中是如何工作的呢?好吧,您手动触发它。

在 React 中,您设置状态的新值,然后导致 ReactDOM.render,从而导致 DOM 比较/更新过程。在 React/Redux 中,您调度更新存储(单一事实来源)的操作,然后是其他操作。重点是,你总是知道什么时候事情发生了变化,以及是什么导致了变化。这使得解决问题非常简单。如果您的应用程序依赖于状态,则在触发更改的操作之前和之后查看它,并确保变量具有它们应该具有的值。

除了实现

从独立于平台的角度来看,它们并没有太大的不同。将单向流与双向绑定分开的是对变化的可变更新。因此,您认为它们在概念上彼此相距不太远的印象并没有脱离它们的实际用途。

在 Angular 中,你有很多控制器。一个例子是用户在控制器 1 管理的视图 1 上触发一个操作。控制器 1 做了一些事情,但也会触发另一个控制器 2 捕获的事件。控制器 2 更新 $scope 上的某些属性,而视图 2 突然改变了。

突然对视图 1 进行了操作,更新了视图 2。如果我们现在加入一些异步回调和更多的事件链,您可能不再确切知道您的视图何时/如何更新。

使用 Flux/Redux,你有一个单向的数据流。视图从不更新模型,视图只能调度一个动作(更新意图),但让 store/reducer 决定如何处理更新。您可以更轻松地推理数据流,因为您可以轻松查看每个视图可以触发哪些操作。然后跟进以查看商店如何处理该操作,您可以确切知道可以更新哪些内容。

  1. 这里的数据流事件——即状态更新

  2. 这些事件在视图和控制器(以及服务,例如 HTTP 后端)之间流动

  3. 单向流基本上就是巨循环:

    • 应用程序视图使用(读取,而不是写入)应用程序状态来呈现
    • 当应用程序从外部获得一些刺激时(用户在输入字段中输入一些文本,或者 HTTP 请求的结果已经到达),它会发出事件 - 或者,在 Redux/Flux 俚语中,分派一个动作
    • 来自所有控制器和视图的所有事件都流入单个接收器 - 调度函数(reducer);尽管调度函数的性质允许它由更简单的调度函数组成,但从概念上讲,整个应用程序只有一个调度程序
    • 调度程序使用事件来确定要更新状态的哪一部分
    • 开始
  4. 双向流又名数据绑定绑定两个状态:在大多数情况下,一个在控制器内部(例如某个变量),另一个在视图内部(例如文本框的内容)。绑定意味着,当一块发生变化时,另一块也会发生变化并获得相同的值,因此您可以假装只涉及一个状态(而实际上有两个)。写入事件在控制器和视图之间来回传递——因此是双向的

  5. 当您需要找出保存此特定文本框内容的变量时,数据绑定很酷 - 它会立即显示。但是它需要复杂的框架来维持一个状态的错觉,而实际上有两个状态。通常,您将被迫使用特定于框架的语法来编写视图代码——即学习另一种语言。

  6. 当您可以利用额外的实体 - 事件流时,单向数据流很酷。而且,通常,您可以 - 它对撤消/重做、用户操作重放(例如用于调试)、复制等很有用。支持这一点的代码要简单得多,通常可以用纯 JavaScript 编写特定于框架的语法。另一方面,由于您不再有数据绑定,它不再为您节省一些样板。

另外,在这个答案中看到很好的视觉解释:https : //stackoverflow.com/a/37566693/1643115单向箭头和双向箭头分别在视觉上表示单向和双向数据流。

假设您的应用程序只是一个向导流程,但它有一些复杂的交互,即一个步骤可能会改变后续步骤的行为。

您的应用程序运行良好,但有一天用户报告了其中一个棘手步骤的错误。

调试如何在双向绑定和单向绑定上工作?

双向绑定

我会开始检查哪些行为是不同的,如果幸运的话,与用户达到相同的点并查明错误。但与此同时,应用程序的不同部分之间可能会有一些奇怪的交互我可能有一些不正确的数据绑定(例如复制模型状态但不绑定)或组件之间难以调试的其他奇怪的复杂性。可能很难隔离错误。

单向绑定

你只需抓住state对象。它在一个大的 javascript 对象中包含当前应用程序的所有信息。您在开发环境中加载相同的状态,您的应用程序很可能会完全相同您甚至可以使用给定的回归状态编写测试并查明正在发生的确切问题。

结论

简而言之,单向绑定使调试复杂的应用程序变得非常容易你不必做太多然后复制用户的当前状态。

即使这不起作用,您也可以记录操作。例如,没有一种简单的方法可以跟踪Angular上的所有状态修改操作。使用 Redux,它非常非常简单