Two-way data binding (Angular) vs one-way data flow (React/Flux)

自古美人都是妖i 提交于 2020-12-27 08:22:35

问题


In the last week, I’ve been trying to make sense how two-way data binding (Angular) and one-way data flow (React/Flux) are different. They say that one-way data flow is more powerful and easier to understand and follow: it is deterministic and helps avoiding side-effects. In my newbie eyes though, they both look pretty much the same: the view listens to the model, and the model reacts on actions done to the view. Both claim that the model is the single source of truth.

Could anybody comprehensively explain in understandable way how they are really different and how one-way data flow is more beneficial and easier to reason about?


回答1:


In Angular you have many controllers. One example would be a user triggering an action on View 1 that is managed by Controller 1. Controller 1 does something but also fires an event that is caught by another Controller 2. Controller 2 updates some property on the $scope and View 2 is suddenly changed.

Suddenly an operation on View 1, updated View 2. If we now throw in some Async callbacks and a bit more event chains, you might no longer know exactly when/how your views are being updated.

With Flux/Redux, you have a one way data flow. The view never updates the model, the views can only dispatch an action (intention to update), but lets the store/reducer deciding how to handle the update. You can more easily reason about the data flow because you can easily see which actions can be fired by each view. Then follow up to see how that action is being handled by the store and you can know exactly what can be updated.




回答2:


Angular's two-way data binding

It's made possible by a mechanism that synchronizes the view and the model whenever either change. In Angular, you update a variable and its change detection mechanism will take care of updating the view, and viceversa. What's the problem? You don't control the change detection mechanism. I found myself having to resort to ChangeDetectorRef.detectChanges or NgZone.run to force the view to update.

To not dive too deep into change detection in Angular, you trust it will update what you need when you change a variable, or when it gets changed after an observable resolves, but you'll find you have no idea how and when it runs, and sometimes it will not update your view after a variable changes. Needless to say, it can sometimes be a pain to find where and when a problem occured.

React's one-way data flow

It means that the view always gets its state from the model. To update the view, you need to update the model first, and then redraw the view. React makes the view redrawing process extremely efficient because it compares not the actual DOM but a virtual DOM it keeps on memory. But how does change detection work in this dynamic? Well, you trigger it manually.

In React, you set the state's new value, which then causes a ReactDOM.render, which causes the DOM comparing/updating process. In React/Redux you dispatch actions which update the store (single source of truth) and then the rest. Point is, you always know when the stuff changes, and what caused the change. This makes problem solving quite straight forward. If your app depends on the state, you look at it before and after the action that triggered the change, and you make sure variables have the value they're supposed to.

Implementations aside

From a platform independent point of view, they're not so different. What separates one-way flow from two-way binding is a variable update on change. So your impression that that they're conceptually not too far from each other is not too divorced from their practical uses.




回答3:


  1. Data flow here is a flow of write events - i.e. state updates

  2. These events are flowing between views and controllers (and services, such as HTTP backends)

  3. One-way flow is basically the giant cycle:

    • app view uses (reads, not writes) app state to render
    • when application gets some stimuli from outside (user typed some text in input field, or result of HTTP request has arrived), it emits write event - or, in Redux/Flux slang, dispatches an action
    • all events, from all controllers and views, are flowing into the single sink - dispatch function (reducer); although the nature of dispatch function allows it to be composed from simpler dispatch functions, conceptually, there's only one dispatcher for the whole app
    • dispatcher uses an event to figure out which part of the state is to be updated
    • go to start
  4. Two-way flow aka data binding binds two pieces of state: in most cases, one inside the controller (e. g. some variable), and one inside the view (e. g. contents of textbox). Binding means that, when one piece changes, the other piece changes as well and gets the same value, so you can pretend that there's only one piece of state involved (while there's two actually). Write events are going back and forth between controllers and views - thus two-way.

  5. Data-binding is cool when you need to figure out what variable holds the contents of this particular textbox - it shows immediately. But it requires complex framework to maintain the illusion of one piece of state where there's two pieces really. Usually you'll be forced to use framework-specific syntax to write your views' code - i. e. to learn yet another language.

  6. One-way data flow is cool when you can leverage that extra entity - events flow. And, usually, you can - it's useful for Undo/Redo, user actions replay (e. g. for debug), replication, etc, etc. And the code to support this is much, much simpler, and usually can be written in plain JavaScript instead of framework-specific syntax. On the other hand, since you no longer have data-binding, it no longer saves you some boilerplate.

Also, see great visual explanation in this answer: https://stackoverflow.com/a/37566693/1643115. Single-headed and two-headed arrows visually represents one-way and two-way data flow respectively.




回答4:


Let's say your app is just a wizard flow, but it has some complex interactions i.e. one step might change a following step behavior.

Your app is running great, but one day an user reports a bug on one of the tricky steps.

How does debugging would work on two-way binding and one-way binding?

Two-way binding

I'd start checking what behavior is different and with some luck, get to the same point as the user and pinpoint the bug. But at the same time there might be some weird interaction between different parts of the app. I might have some data-binding that is incorrect (e.g. replicating the model state but not binding) or other weird intricacy between components that is hard to debug. It might be hard to isolate the bug.

One-way binding

You just grab the state object. It has all the information of the app currently in a big javascript object. You load the same state in your development environment, there is a big chance your app will behave exactly the same. You can even write a test with the given state for regression and pinpoint the exact problem that is happening.

Conclusion

In a few words, one-way binding makes it very easy to debug complex apps. You don't have to do much then copy over the current state of the user.

Even that doesn't work, you can log the actions as well. There isn't AFAIR an easy way to track all the state modifying actions on Angular, for instance. With Redux it's pretty, pretty easy.



来源:https://stackoverflow.com/questions/34565568/two-way-data-binding-angular-vs-one-way-data-flow-react-flux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!