在上周,我一直试图理解two-way data binding (Angular)和one-way data flow (React/Flux)的不同之处。他们说单向数据流更强大,更容易理解和遵循:它是确定性的,有助于避免副作用。在我的新手眼中,它们看起来几乎相同:视图监听模型,模型对视图所做的操作作出反应。两者都声称模型是单真相来源。
任何人都能以可理解的方式全面解释他们真正的不同之处以及单向数据流如何更有益且更容易推理?
答案 0 :(得分:9)
在Angular中你有很多控制器。一个示例是用户触发由控制器1管理的视图1上的操作。控制器1执行某些操作但也触发由另一个控制器2捕获的事件。控制器2更新$ scope上的某些属性,而视图2突然显示改变。
突然对View 1进行操作,更新了View 2.如果我们现在引入一些Async回调和更多的事件链,您可能不再确切知道您的视图何时/如何更新。
使用Flux / Redux,您可以使用单向数据流。视图永远不会更新模型,视图只能调度操作(更新意图),但让store / reducer决定如何处理更新。您可以更轻松地推断数据流,因为您可以轻松查看每个视图可以触发的操作。然后跟进以查看商店如何处理该操作,您可以确切地知道可以更新的内容。
答案 1 :(得分:4)
我们假设您的应用只是一个向导流,但它有一些复杂的互动,即一步可能改变后续步骤行为。
您的应用运行良好,但有一天用户会报告其中一个棘手步骤的错误。
如何在双向绑定和单向绑定上进行调试?
我开始检查哪些行为有所不同,并且运气好,与用户达到相同的点并查明错误。但同时应用程序的不同部分之间可能会有一些奇怪的交互。我可能有一些不正确的数据绑定(例如复制模型状态但不绑定)或难以调试的组件之间的其他奇怪的复杂性。 隔离错误可能很难。
您只需抓住state
对象即可。它包含当前在大型javascript对象中的应用程序的所有信息。您在开发环境中加载相同的状态,很有可能您的应用程序的行为完全相同。您甚至可以编写具有给定状态的测试用于回归并确定正在发生的确切问题。
简而言之,单向绑定使得非常容易调试复杂的应用程序。您不必做太多事情,然后复制用户的当前状态。
即使这不起作用,您也可以记录操作。例如,AFAIR没有一种简单的方法来跟踪Angular上的所有状态修改操作。使用Redux,它非常简单。
答案 2 :(得分:3)
数据流此处是写入事件的流程 - 即状态更新
这些事件在视图和控制器(以及服务,如HTTP后端)之间流动
单向流基本上是一个巨大的循环:
双向流又名数据绑定绑定两个状态:在大多数情况下,一个在控制器内部(例如某个变量),一个在内部视图(例如文本框的内容)。 绑定意味着,当一个部分发生变化时,另一个部分也会发生变化并获得相同的值,因此您可以假装只涉及一个状态(实际上只有两个)。 写入事件在控制器和视图之间来回传递 - 因此双向。
当您需要确定哪个变量包含此特定文本框的内容时,数据绑定很酷 - 它会立即显示。但它需要复杂的框架来维持一个国家的错觉,其中有两件真的。通常,您将被迫使用特定于框架的语法来编写视图的代码 - i。即学习另一种语言。
当您可以利用额外的实体 - 事件流时,单向数据流很酷。而且,通常,你可以 - 它对Undo / Redo,用户动作重放(例如调试),复制等等很有用。支持它的代码要简单得多,而且通常可以用纯JavaScript编写代码特定于框架的语法。另一方面,由于您不再拥有数据绑定,它不再为您节省一些样板。
此外,请参阅此答案中的精彩视觉解释:https://stackoverflow.com/a/37566693/1643115。单头和双头箭头分别直观地表示单向和双向数据流。
答案 3 :(得分:3)
它可以通过一种机制实现,无论何时更改,都可以同步视图和模型。在Angular中,您更新变量,其更改检测机制将负责更新视图,反之亦然。问题是什么?您无法控制变更检测机制。我发现自己不得不求助于ChangeDetectorRef.detectChanges或NgZone.run来强制视图更新。
为了不深入研究Angular中的变化检测,你相信它会在你改变一个变量时更新你需要的东西,或者在一个observable结算后它会被改变,但是你会发现你不知道如何当它运行时,有时在变量变化后它不会更新你的视图。不用说,它有时可以 找到问题发生的地点和时间很痛苦。
这意味着视图总是从模型中获取其状态。要更新视图,首先需要更新模型,然后重绘视图。 React使视图重绘过程非常高效,因为它不是实际的DOM,而是它在内存中保留的虚拟DOM。但是,变化检测如何在这种动态中发挥作用?好吧,你手动触发它。
在React中,设置状态的新值,然后生成ReactDOM.render,从而导致DOM比较/更新过程。在React / Redux中,您可以调度更新商店的操作(单一事实来源),然后是其他操作。重点是,你总是知道什么东西改变,以及是什么导致了改变。这使问题解决非常直接。如果您的应用程序取决于状态,则在触发更改的操作之前和之后查看它,并确保变量具有它们应该具有的值。
从平台独立的角度来看,他们并没有那么不同。单向流与双向绑定的区别在于变化的可变更新。所以你的印象是,他们在概念上彼此之间的距离并不太远,不能脱离实际用途。