3 ms·
In WPF, you call OnPropertyChanged on the setter of a property, giving you two-way data binding. Great, now you can modify the model directly from the view. The
by samizdatum 11y ago
In WPF, you call OnPropertyChanged on the setter of a property, giving you two-way data binding. Great, now you can modify the model directly from the view. The problem is that modifying the models directly from the views makes it really difficult to reason about your dataflows. It's not unusual to have the same model bound to five or ten different views. Run your WPF application for a while, and- hang on- this view isn't showing the correct data. This kind of scenario is hellish to debug, because there's so many places that could have mutated the model.
In a large application using two-way binding, the application state is implicit in its execution. There's thousands of places that mutate the state, so many that if you tried to make a graph of the dataflows, you'd get spaghetti. Sure, the code is neat and simple, but you know you've got a problem when the dependency graph is so complex that you can write a cyclic binding and not even realise it.
Redux borrows a lot from functional techniques to tackle these kinds of problems. The big one is that you can't mutate the state, because it's immutable. Instead, you write reducing functions that take an application state and an action, and return a completely new application state based on that action (which might sound wasteful until you learn about functional data structures).
This buys you a lot of things. You can hang on to your old application states instead of throwing them away, and then, very easily, set up a slider that lets you "time travel" in your application. You can grab a list of actions, and feed them to a hundred instances of your application, all with different initial states, and inspect how the state changed at each action- really useful for testing or debugging. You can completely change your code, and have the application update in real time with all the state intact, but now running your new code- this really speeds up development. You can catch errors, and then automatically send a complete snapshot of the application state (complete with where the focus was, the text the user was typing, the clicks they used to get to that particular screen, etc.) and then play it back, allowing you to perfectly reproduce the error.
These things are all extremely difficult when the state of your application (and how it changes over time) is implicit and scattered over hundreds of views. It's trivial when the state of your application is completely described by an initial state, a series of actions, and a single reducing function.
Regarding the "intermediate information" you alluded to: this is generally solved by using something like reselect, which allows you to define transformations on the state that can be fed to views. For example, you could write a function that returns a list of items in the state that match a search query in the state, but not have the resulting list itself live in the state. This means you still have one source of truth, and the immutability of the state ensures you don't lose any of the benefits I listed above.