As I've been learning about ReactJS and now, starting to learn about Flux, I tend to see a lot of writing on the "how" things work but not necessarily the "why" things work the way they do. As such, I am finding it difficult to build a mental model of how all the choices fit together. One such point of non-clarity is whether or not the very existence of Flux should change the way that I think about building ReactJS components?
Right now, in my mind, Flux is the way that I manage state over which a given Component does not have dominion. Meaning, Flux is how I manage the state that is provided to the Component as opposed to the state that is controlled by the component. As such, in my mind, a Component can be "white paged" with mock data and then Flux can be added later on in the development and integration life cycle when a back-end exists and data can be persisted.
Such a swap would require all of the top-level mutation methods, of a Controller view, to stop mutating mock data and start triggering Actions that propagate to Stores that propagate back to Components. In my mind, this is a relatively easy change since the top-level component, of a cohesive widget, encapsulates all of this interaction and just passes state and mutation methods down to its children. The children can remain blissfully unaware to any of the changes in persistence and / or data management.
Keep in mind that what I have just described is absolutely "one way data flow." Nothing mutates state except for the component that owns it.
Where I get confused is that I see people starting to store "User Interface State" (UI State) in Stores, using the Flux design patterns. This confuses me because it seems to transform Flux into a user interface (UI) design choice and not a data management architecture and implementation detail. Meaning, Flux now becomes an integral part of how a ReactJS component is actually built.
Which begs the question: When building a ReactJS component, is Flux the very first decision you need to make? Or the very last?
I keep thinking back to Uncle Bob Martin saying (and I'm paraphrasing), "A good architecture lets you defer as many choices as possible." Now, I am in no way a good architect - so, I don't bring this up in an Ivory Tower sense; I bring it up because I am lost and I am having trouble reconciling all of the things.
As a side note ... Right now, my mental model hinges heavily on Browser Refresh. Meaning, if I refresh the browser and I want something to stay the same, it goes in a Store. However, if I refresh the browser and I don't want something to stay the same, it goes in the state of a component.
Anyway, this is all confuses as heck. But, I will muscle through and continue to build my mental model.
Great points Ben. I'm also learning React, and the first step fort me is deciding on the component tree. Once you have that, it is easier to fit the component or component hierarchy with a store, and see what actions the components should propagate.
Just curious, what flux implementation do you use? Did you do any comparison with different flux libraries?
Honestly, I haven't actually implemented any of the different patterns. Right now, in my tinkering, it's all "white page" experiments with the in-browser JSX Transformer. As such, I haven't actually even tried to use a Store yet. Part of that is that I am still just learning about ReactJS; but, part of that is that reading about it still confuses me, hence posts like this.
Long store short, I haven't read up on any of the alternate forms of Flux, like Flummox, Reflux, Redux, etc... my brain already hurts enough :D
The way I see it, Flux lets you have a global shared state, so if you have to make components that lie in a variety of places share things, then thinking the app with flux from the start makes sense.
I think that makes perfect sense. But, a lot of the things I have been seeing are where a Store is referenced directly by nested components inside of a single cohesive unit of functionality. Meaning, if I had a Table that had Rows, I keep seeing instances where both the Table and the Row components reference the store, instead of having data just passed into the Row as props. This is where I start to get fuzzy on why that is happening.
I assume that it is "easier" to reference a Store than to think about the structure of Props and what needs to go where. But, I wonder if that is also a bandaid on top of another problem? I'm not really sure yet.
The table / rows example would be a simple case where passing props down could work, so in this case it would not be necessary to connect components individually to flux.
But imagine that in this table you list things that people can like, and you want to display the number of likes for each item, and a button to favorite items if it has not been liked yet by the user.
Passing props down would not work here, you'd need to connect 2 stores, one for the items and one for the favorites of the user, probably passing item props.id to the store to get its status.
The concept generally used is "dumb components" and "smart components" : dumb components don't know about flux, they just have simple props like "badgeCount", where smart components wrap the dumb components to connect them to stores, so a prop "badgeCount" would be connected to the "likes" stores. Now if you want to render an "item" component displaying a badge with the "likes" count, just drop the smart component anywhere with an "id" prop, it will display the number of likes wherever it is in the app, and it does not have to be in a container passing props to work.
Makes sense ?
I think that makes sense when the "smart component" is only tangentially relevant to the context in which it is placed. Meaning, it is intended to exist and function very independently.
I think where I see **what I perceive** as incorrect usage of stores is when they take "dumb components" and connect them to a store for the *sole purpose* of not wanting to pass around props.
Anyway, I still haven't played with stores yet :(