Search code examples
javascriptreactjsrefluxjs

How to connect my react component to reflux store?


I am kinda new to React and Reflux and modern JavaScript development. Trying to learn. So, I am making a component that is basically a sort of a chat window. A list with lines and an input box. When you type something into the input box and hit enter it adds the line to the list. I made it work with pure React using setState() and now I want to make it use a Reflux store. My component code goes like this

import React from 'react';
import Reflux from 'reflux';

import ConsoleActions from '../actions';
import ConsoleStore from '../stores';

export default React.createClass({
  mixins: [Reflux.connect(ConsoleStore, "lines")],
  render() {
    var lines = this.state.lines.map(function(line) {
      return(<li>{line}</li>)
    });
    return (
       <ul>{lines}</ul>
       <input onKeyUp={this.enter}/>
    )
  },
  enter(e) {
    if (e.keyCode == 13) {
      ConsoleActions.addConsoleLines([e.target.value]);
      e.target.value = null
    }
  }
});

my actions are

import Reflux from 'reflux';

export default Reflux.createActions(["addConsoleLines","clearConsoleLog",]);

and my store is import Reflux from 'reflux';

import Actions from './actions';

export default Reflux.createStore({
  lines: [],
  listenables: Actions,

  getInitialState: function() {
    return [];
  },

  addConsoleLines(lines) {
    lines.forEach(line => {
      this.lines.append(line);
    });
  },

  clearConsoleLog() {
    this.lines = []
  }
});

Not sure what I am missing, Reflux.connect() should connect my store to state, but I get "TypeError: this.state.lines is undefined" error.


Solution

  • You should trigger change event when lines appended.

    export default Reflux.createStore({
      listenables: [Actions],
      lines:[],
      addConsoleLines(lines) {
        let self=this;
        lines.forEach(line => {
          self.lines.append(line);
        });
        self.trigger('change',self.lines);
      },
    
      clearConsoleLog() {
        this.lines = []
      }
    });
    

    And in your component listen for that change event

    export default React.createClass({
      mixins: [Reflux.connect(ConsoleStore, "onChange")],
      onChange(event,_lines){
             this.setState({lines:_lines});
        }
      render() {
        var lines = this.state.lines.map(function(line) {
          return(<li>{line}</li>)
        });
        return (
           <ul>{lines}</ul>
           <input onKeyUp={this.enter}/>
        )
      },
      enter(e) {
        if (e.keyCode == 13) {
          Actions.addConsoleLines([e.target.value]);
          e.target.value = null
        }
      }
    });
    

    Edit1: Yes you are correct. There is another simple way to this. The Reflux.connect() mixin will check the store for a getInitialState method. If found it will set the components getInitialState. I think you forgot to return the initial state.

    export default Reflux.createStore({
      listenables: Actions,
    
      getInitialState() {
            return [];
        },
    
      addConsoleLines(lines) {
       ...
      }