Search code examples
javascriptreactjsreactjs-fluxfluxible

Reactjs, parent component, state and props


I m actually learning reactjs and I m actually developping a little TODO list, wrapped inside of a "parent component" called TODO.

Inside of this parent, I want to get the current state of the TODO from the concerned store, and then pass this state to child component as property.

The problem is that I dont know where to initialize my parent state values.

In fact, I m using ES6 syntax, and so, I dont have getInitialState() function. It's written in the documentation that I should use component constructor to initialize these state values.

The fact is that if I want to initialize the state inside of my constructor, the this.context (Fluxible Context) is undefined actually.

I decided to move the initialization inside of componentDidMount, but it seems to be an anti pattern, and I need another solution. Can you help me ?

Here's my actual code :

import React from 'react';
import TodoTable from './TodoTable';
import ListStore from '../stores/ListStore';

class Todo extends React.Component {

  constructor(props){
    super(props);
    this.state = {listItem:[]};
    this._onStoreChange = this._onStoreChange.bind(this);
  }

  static contextTypes = {
      executeAction: React.PropTypes.func.isRequired,
      getStore: React.PropTypes.func.isRequired
  };

  componentDidMount() {
      this.setState(this.getStoreState()); // this is what I need to move inside of the constructor
      this.context.getStore(ListStore).addChangeListener(this._onStoreChange);
  }

  componentWillUnmount() {
      this.context.getStore(ListStore).removeChangeListener(this._onStoreChange);
  }

  _onStoreChange () {
   this.setState(this.getStoreState());
 }

  getStoreState() {
      return {
          listItem: this.context.getStore(ListStore).getItems() // gives undefined
      }
  }

  add(e){
    this.context.executeAction(function (actionContext, payload, done) {
        actionContext.dispatch('ADD_ITEM', {name:'toto', key:new Date().getTime()});
    });
  }


  render() {
    return (
      <div>
        <button className='waves-effect waves-light btn' onClick={this.add.bind(this)}>Add</button>
        <TodoTable listItems={this.state.listItem}></TodoTable>
      </div>
    );
  }
}


export default Todo;

Solution

  • As a Fluxible user you should benefit from Fluxible addons:

    The following example will listen to changes in FooStore and BarStore and pass foo and bar as props to the Component when it is instantiated.

    class Component extends React.Component {
        render() {
            return (
                <ul>
                    <li>{this.props.foo}</li>
                    <li>{this.props.bar}</li>
                </ul>
            );
        }
    }
    
    Component = connectToStores(Component, [FooStore, BarStore], (context, props) => ({
        foo: context.getStore(FooStore).getFoo(),
        bar: context.getStore(BarStore).getBar()
    }));
    
    export default Component;
    

    Look into fluxible example for more details. Code exсerpt:

    var connectToStores = require('fluxible-addons-react/connectToStores');
    var TodoStore = require('../stores/TodoStore');
    ...
    
    TodoApp = connectToStores(TodoApp, [TodoStore], function (context, props) {
        return {
            items: context.getStore(TodoStore).getAll()
        };
    });
    

    As a result you wouldn't need to call setState, all store data will be in component's props.