Search code examples
javascriptreactjsreactjs-fluxfluxible

Reactjs getting event from store with fluxible


Hi I m actually trying to developp a little applications using flux, reactjs and fluxible and I m facing a problem when dealing with stores.

In fact, I can send information to my store through actions, but I dont know how to receive the result of this.emitChange in stores inside of my component to refresh the screen.

What should I put in my component to refresh my list ?

Here's my component :

import React from 'react';

class Client extends React.Component {

    constructor (props) {
      super(props);
      this.myListView = [];
    }

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

    render() {
        return (
            <div>
                <h2>Client</h2>
                <p>List of all the clients</p>
                <button onClick={this.add.bind(this)}>Click Me</button>
                <ul>
                    {this.myListView.map(function(title) {
                      return <li key={name}>{name}</li>;
                    })}
                </ul>
            </div>
        );
    }
}


Client.contextTypes = {
    executeAction: React.PropTypes.func.isRequired
};

export default Client;

Here's my store

import BaseStore from 'fluxible/addons/BaseStore';

class ListStore extends BaseStore {

  constructor(dispatcher) {
      super(dispatcher);
      this.listOfClient = [];
    }

  dehydrate() {
      return {
          listOfClient: this.listOfClient
      };
  }

  rehydrate(state) {
      this.listOfClient = state.listOfClient;
  }


  addItem(item){
    this.listOfClient.push(item);
    this.emitChange();
  }

}

ListStore.storeName = 'ListStore';
ListStore.handlers = {
    'ADD_ITEM': 'addItem'
};

export default ListStore;

UPDATE

this.setState is not well applied

_onStoreChange() {
      console.log(this.getStoreState()) // gives me the good list
      this.setState(this.getStoreState()); // doesn't update the list, this.myListView gives [] always
    }

Solution

  • You probably want to put myListView into the component's state and populate it from the store on instantiation.

    So your component will end up something like:

    import ListStore from '../stores/ListStore';
    class MyComponent extends React.Component {
        static contextTypes = {
            getStore: React.PropTypes.func.isRequired,
            executeAction: React.PropTypes.func.isRequired
        }
    
        constructor(props) {
            super(props);
            this.state = this.getStoreState();
            this.boundChangeListener = this._onStoreChange.bind(this);
        }
        getStoreState () {
            return {
                myListView: this.context.getStore(ListStore).getItems()
            }
        }
        componentDidMount () {
            this.context.getStore(ListStore).addChangeListener(this.boundChangeListener);
        }
        componentWillUnmount () {
            this.context.getStore(ListStore).removeChangeListener(this.boundChangeListener);
        }
        _onStoreChange () {
            this.setState(this.getStoreState());
        }
        add(e){
          this.context.executeAction(function (actionContext, payload, done) {
              actionContext.dispatch('ADD_ITEM', {name:'toto'});
           });
        }
        render () {
        return (
            <div>
                <h2>Client</h2>
                <p>List of all the clients</p>
                <button onClick={this.add.bind(this)}>Click Me</button>
                <ul>
                    {this.state.myListView.map(function(title) {
                      return <li key={name}>{name}</li>;
                    })}
                </ul>
            </div>
        );
        }
    }
    

    This way you'll listen to changes and trigger setState on the component, causing a re-render.

    Update to the add method

    In the original code above, I'm not sure the way the action is executed on click is correct. Perhaps try:

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