React + Flux - should store data be stored in a component state, or props? React + Flux - should store data be stored in a component state, or props? reactjs reactjs

React + Flux - should store data be stored in a component state, or props?


Understand that you should have 2 kinds of components. Stateful components and view components.

Stateful components can have 3 kinds of states: initial state, user input state, and data store state.

Stateful components are like small entry points in the "widget" that you're assembling. There is no single application-wide entry point anymore for downstream dependency or data injection, because all of these widgets have their own isolated lifecycles. That's why they themselves need to access & listen to stores.

Besides behavorial properties, stateful components do not receive actual data via upstream properties.

Stateful components manage their own state and pass it to their children to render through downstream properties.

Stateful components do not normally render html DOM elements themselves directly. They're more like the controllers in MVC, and use other dumber components, the ones like views in MVC, to actually render DOM elements.

Dumber components are like views so they only contain logic to render DOM elements. Think of them as handlebars.js templates that only receive properties, and simply render those into DOM elements possibly with loops etc. They are stateless renderers.

Hope this answers your question.


According to formal documentation, a store should update the parent component's state, and pass it down via his children props:

When it receives the event from the store, it first requests the new data it needs via the stores' public getter methods. It then calls its own setState() or forceUpdate() methods, causing its render() method and the render() method of all its descendants to run.

We often pass the entire state of the store down the chain of views in a single object, allowing different descendants to use what they need. In addition to keeping the controller-like behavior at the top of the hierarchy, and thus keeping our descendant views as functionally pure as possible, passing down the entire state of the store in a single object also has the effect of reducing the number of props we need to manage.

(facebook flux docs - Overview)


It makes more sense to put store data in the component's state, this is because props may change by a parent component with componentWillReceiveProps. So it makes sense to update the state whenever:

  • the store's change event is fired and
  • whenever the props change (putting derivative data related only to the component itself to the state)

Below is a sample component that updates listening to a reflux store and also on props change. I rarely use this.props in the render function, instead I amend them (create derivative data that is only used within the component itself) as new props come in. I constantly run into this pattern so might as well write this down:

var SampleComponent = React.createClass({    mixins: [Reflux.ListenerMixin],    // reusable helper function to build state object    buildStateFromProps: function(props) {        return {            actualHeight: props.height + 20        }    },    // default props if no such was set by a parent component    getDefaultProps: function() {        return {            height: 100        };    },    // initial state with all value set to something default    // even using buildStateFromProps with default props    getInitialState: function() {        // this.props is built before this.state        var state = buildStateFromProps(this.props);        // append default data from store        state.text = '';    },    // happens when the parent component send different     // props data    componentWillReceiveProps: function(nextProps) {        // building derivative data from new props        // reusing buildStateFromProps        this.setState(buildStateFromProps(nextProps));    },    // setting up store to be used by the component    componentDidMount: function() {        // this.listenTo is a helper function ListenerMixin        this.listenTo(sampleStore, sampleUpdated);    },    // is called from the sampleStore update    sampleUpdated: function(sampleData) {        this.setState({            text: sampleData.text        });    },    render: function() {        return (            // ...             // using this.state.text from store updates and            // this.state.height from prop updates        );    }});

The reason I send props data to state is to avoid cluttering up the render function. Otherwise the render function will contain a lot of code that is not really related to "rendering" the component. Furthermore if this derivative data is used in other parts of the application then it is easy to pull it out from the component and put it into the store.

Hope this helps.