Multiple React components, one store

Codrin Iftimie
Front-end Development
4 min readNov 9, 2014

--

Flux is an architecture that handles information flow better than the traditional MVC or MV* frameworks. Forget two way bindings, multiple controllers that depend on each other and overly complicated events that updates models.

I really dig what Facebook has open sourced, especially on the frontend side of the web. Most of the things they get out solve real problems other frameworks would not even touch. Also they do play well with everything. Flux can be used as a stand alone architecture for managing aplication flow that you can use in a jQuery project. React is that good that is being used as a rendering layer by other developers with frameworks like: Angular, Backbone and even Ember.

The problem with React is that he relies on event propagation. This means that if you want a element to affect another that is upper in the tree you have to send a prop to all of the sub-elements until it reaches the one that is interested in doing something with that callback. This is a bit expensive because the previous implementation was to send the props to it’s children. With 0.12 they deprecated this solution, and advised us to use {…<props>} instead. This only improves the rendering time, but doesn't solve the problem. This is where flux comes in.

The only thing you have to do is to create a flux dispacher, that will be available via a mixin or as a singleton in your app, to all components that will need to interact with state that is not it’s own. There are numerous implementations out there like: facebook/flux, fluxxor, reflux, yahoo/dispachr. Since fluxxor was the first out, it will always be my favorite.

http://fluxxor.com/what-is-flux.html

The flux principle is simple: the dispacher will listen to actions from the views(react elements) that will update one or more stores. The stores will then tell the views that are listening to update their state using their data.

While using flux, I've encountered a problem with this architecture. It’s stores are singletons, and the react elements that will listen to a store should be instantiated only once in an app.

The problem

Let’s say you want to display two tables and you have a React component called Table, that listens to a TableStore. By clicking a table header column, you will sort the data ascending or descending.

When you mount one table in your app, everything is ok, but when adding two ore more, you will soon notice those tables are syncing, when clicking their table header columns. You won’t be able to reuse this table component with a flux store watch mixin.

What is the solution?

There are a few ways to tackle this problem.

You can make an extra store, and create a React component factory, that will add the right store watch mixin to your component. But this is unpractical and won’t scale. You will end up with sending the store the view is using to actions.

You might as well create different flux instances, with the same actions and store, which may work, but you will loose the flux way of interacting with the rest of your app.

var flux1 = new fluxxor.Flux(store, actions),
flux2 = new fluxxor.Flix(store, actions);
...
<Table flux={flux1} />
<Table flux={flux2} />

You can use a unique identifier for each table by using a prop (the ref prop sounds logic enough), and create (if not already there) a sub-store when the component will mount, by sending it’s ref.

componentWillMount: function() {
this.getFlux().actions
.createSubstore(this.props.ref, "TableStore");
}

When updating the stores, the component will only take the state of it’s ref prop sub-store. This also means that when the component will mount again it will have the previous state, unless you tell it not to (by re-initiating the sub-store).

getStateFromFlux: function(){
this.getFlux.store("TableStore").getState(this.props.ref);
}

This solution is mostly the same as managing those tables at a higher level, and sending the sorted data as props:

displayName: "TablesManager",
...
render: function(){
<Table rows={this.state.table1} />
<Table rows={this.state.table2} />
}

Rendering time should be the same, since the “TablesManager” will re-render whenever one table will change; or in the case of using a store watch mixin, both Tables will re-render since they listen to the same store change.

The good thing about React is that it has the virtual DOM diffing that will only update the right component. I’d still go with a store watch aproach since it triggers the rendering of all of its Table instances, not the whole TablesManager, which is super usefull when you have other components inside it.

I’m working on creating an extra Mixin for fluxxor, that will make multiple components that listen to the same store, a dream came true. I didn’t had much time to look over the rest of the Flux arhitecture solutions out there, but I think this problem is universal.

Update: Facebook’s way

They are using containers to send the rendering data to a reusable component. More here: https://youtu.be/KYzlpRvWZ6c?t=22m51s

As always comments, tweets and recommendations are welcome.

--

--

Codrin Iftimie
Front-end Development

would like to save the web • movie enthusiast • accidentally brilliant at times • frontend technical lead @ bytex