The Flux architecture Benjamin Encz describes for the PlanGrid iOS app is like ReSwift only on a per-component basis: the user interactions fire change events that a store takes care of to mutate its state. The state then becomes the input for the view again.
It’s much like MVVM, whereas here the view model is the store’s state.
This Flux-like approach is still a big improvement over convoluted view controllers or not thinking about data flow at all. But I wonder if the gain is so much higher compared to properly separated MVC. Who reads the store’s state? Only the views? Then the state is truly a view model; but how do side-effect populate to the rest of the app, like renaming or deleting things? I’d tend towards dispatching the change event to other stores, too, which may or may not react to the event. Then the view component’s state is updated independently from the database, say, using the same event dispatch mechanism.
To model the flow of truth on a component basis (which is still uni-directional: from store to view) compared to a single global app state (ReSwift) sounds like a very easy to do component redesign. You can start with anything and “fluxify” it. Then move on to the next component that’s particularly convoluted. You may not even want to convert all your components to this data flow approach when some components are simple enough as they are. Symmetry of component design will suffer, of course, but if you’re aware of this and conclude it’s better not to convert everything, that’s fine.
With ReSwift, I interpret the global app state to be a state with real (Domain) Model objects. To make a state displayable, I derive view models from it. This came very natural to me. But Ben’s posts got me thinking: could there be situations where keeping view model state around is better than keeping “real” model state?
Benjamin Encz published an article about the architecture of PlanGrid.
They moved to a Flux-inspired “unidirectional flow” approach where state changes are performed in a
Store (in the backend, if you will) and updates pushed to the user interface (the frontend). No ad-hoc view updates, no shortcuts. User events are emitted, handled by the store, and state updates affect the view. That’s it. So it’s always obvious how the user interface got into the state it’s in: all the details are plainly visible in the current state object.
Ben’s post is very deep and detailed. You’ll learn a ton from it:
- architectural discussion: why “unidirection flow”, and why Flux?
- setup of actions/events and the store type
- basic state–view bindings via Reactive Cocoa
- how testing stores (and views) is straightforward with this setup
I can’t wait for the next post in this series. Most of this easily applies to ReSwift, too, of course. And guess who just got inspired to refactor TableFlip so the model and view become even more loosely coupled?