Search code examples
reactjsfluxible

How to update state vs props in a fluxible react.js component using connectToStores


So I'm not sure I quite understand what connectToStores is doing in my search results component. I'm expecting the component's state to be updated when my store emits changes, however it only seems to be updating the properties of the component and updates the state of a wrapping SearchResultsConnector object.

My questions are:

  1. Am I not supposed to be using state in this case, if so, why does the connectToStores have a callback that returns the state?

  2. When does state get updated from an emitChanges trigger in the store? Do I have to duplicate what I did in the constructor?

  3. When should I use state vs props, and should store update state at all? is there a specific flux rule that props mutate state in a one way fashion?

  4. Why does state update to the results when I hot-load changes in the dev-server. I don't understand if that's correct behavior.

  5. Should I be catching an update event somewhere here and updating the state with the incoming changed properties somehow?

SearchResults.js

import React from 'react';
import SearchStore from '../stores/SearchStore';
import Product from './Product';
import connectToStores from 'fluxible-addons-react/connectToStores'


class SearchResults extends React.Component {

    static contextTypes = {
        executeAction: React.PropTypes.func.isRequired,
        getStore: React.PropTypes.func.isRequired
    };
    static propTypes = {
        results: React.PropTypes.array
    };
    static defaultProps = {
        results:[]
    };
    constructor(props) {
        super(props);
        this.state = {results: props.results};
    }
    render() {

        let main;

        // I first used this.state.results, but this.state is null unless I hot load from the dev server on changes
        if (this.props && this.props.results && this.props.results.length) {

            let products = this.props.results.map(function (product) {
                return (
                    <Product
                        key={product.id}
                        imageUrl={product.image_url_large}
                        description={product.description}
                        name={product.name}
                        maxPrice={product.price_max}
                        minPrice={product.price_min}
                    />
                );
            }, this);

            main = (
                <section id="results">
                    <ul id="todo-list">
                        {products}
                    </ul>
                </section>
            );
        }

        return (
            <div>
                <header id="header">
                    <h1>Search Results</h1>
                </header>
                {main}
            </div>
        );
    }

}

SearchResults = connectToStores(SearchResults, [SearchStore], (context, props) => ({
    results: context.getStore('SearchStore').getResults()
}))


export default SearchResults;

Solution

  • connectToStores is a function that returns a 'higher order component' base on the component you provide (the SearchResults you put in as the first parameter).

    If you look at the implementation here (line #44, the render method of storeConnector), it basically transfer the states you provide to the props of the returned object. So yes, you should be getting the value from props in your component for rendering, instead of state.

    If you are interested to know why should we use higher order component, you can take a look at this article