I find the example todo flux app to be a bit lacking so I'm trying to get my head round things by developing an application to learn and experiment.
The application is a drag and drop fruit basket organiser. I have several baskets which can have various pieces of fruit dragged between them. You can highlight a piece of fruit by clicking on it and the last dragged item will remain highlighted.
Based on this I have 3 stores:
When a user action occurs a FruitAction is dispatched and handled by either the AppStateStore if the fruit has been clicked or all stores if the fruit has been moved to another basket.
The main AppView component listens to change events from both the FruitStore and the AppStateStore and re-renders.
My questions are:
What is flux. Flux is a pattern for managing how data flows through a React application. As we've seen, the preferred method of working with React components is through passing data from one parent component to it's children components. The Flux pattern makes this model the default method for handling data.
What are Stores? In Flux, Stores are simply a place where data is read out from. More specifically, Views within a Flux architecture will be notified of changes within Stores via the Observer pattern, and then query for those data in order to update their own states.
Node's event emitter is used to update the store and broadcast the update to view. The view never directly updates the application state. It is updated because of the changes to the store. This is only part of Flux that can update the data.
Flux is an application architecture that Facebook uses internally for building the client-side web application with React. It is not a library nor a framework. It is neither a library nor a framework. It is a kind of architecture that complements React as view and follows the concept of Unidirectional Data Flow model.
FruitClicked
and FruitDragged
could both be actions, and the stores would watch for the ones they care about.AppView
should listen to all the stores that it gets data from. If you call setState
more than once in the same tick, React will intelligently merge them, so you're not actually rendering more than once.The article on the React site does talk about actions that dispatch themselves under Creating Semantic Actions. In the code block a few scroll-lenghts up the page, you can see the code:
_onDestroyClick: function() {
TodoActions.destroy(this.props.todo.id);
}
The article also talks about which components should listen to stores in Listening to Changes with a Controller-View:
We need a React component near the top of our component hierarchy to listen for changes in the store. In a larger app, we would have more of these listening components, perhaps one for every section of the page. In Facebook's Ads Creation Tool, we have many of these controller-like views, each governing a specific section of the UI. In the Lookback Video Editor, we only had two: one for the animated preview and one for the image selection interface.
and
Occasionally we may need to add additional controller-views deeper in the hierarchy to keep components simple. This might help us to better encapsulate a section of the hierarchy related to a specific data domain. Be aware, however, that controller-views deeper in the hierarchy can violate the singular flow of data by introducing a new, potentially conflicting entry point for the data flow. In making the decision of whether to add a deep controller-view, balance the gain of simpler components against the complexity of multiple data updates flowing into the hierarchy at different points. These multiple data updates can lead to odd effects, with React's render method getting invoked repeatedly by updates from different controller-views, potentially increasing the difficulty of debugging.
It's hard to say whether the approach is a good one without understanding the application a bit more.
However, it seems to me that clicking the fruit should be handled by the FruitStore. That is, a fruit has gained an active state, has become draggable. If this affects the application as a whole somehow, then perhaps this would cause a change in the AppStateStore as well. Likewise, moving a fruit from one basket to another seems like the domain of the BasketStore.
I imagine the FruitStore containing a private data structure like this:
var _fruit = {
1234: {
id: '1234',
type: 'apple',
active: false
},
2345: {
id: '2345',
type: 'orange',
active: false
},
3456: {
id: '3456',
type: 'apple',
active: false
}
};
and I imagine the BasketStore having a private data structure that looks like this:
var _baskets = {
4321: {
id: '4321',
name: 'Josephine\'s Basket',
fruitIDs: [
1234,
2345
]
},
5432: {
id: '5432',
name: 'Harold\'s Basket',
fruitIDs: [
3456
]
}
};
Thus the fruit "active" state is managed by the FruitStore, and the contents of the baskets are managed by the BasketStore.
So the AppView can listen to both stores, if this works well for your application. And as mentioned above, there is very little cost to calling the render() method repeatedly. This does not touch the DOM on every call -- this is one of React's greatest strengths. React will instead intelligently batch the calls and only update the "dirty" parts of the DOM, if any exist.
But perhaps you might want to have the baskets become controller-views. If you do choose to make your fruit the controller-views, be sure to cleanup the listeners in componentWillUnmount(), as the movement of fruit from basket to basket may require them to be destroyed and recreated. I think listening at the basket level makes more sense, but again, I don't understand your app that well.
To answer your last question:
Is there a more complete example of the Flux architecture or something similar?
Engineers at Facebook are working on a more complex application example now that will showcase the use of waitFor() and server-side persistent storage. We are hoping to release that soon.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With