2
votes

For some reason, every time I trigger an action in my react component, the store method associated with the action gets triggers twice. Using the Firefox debugger I noticed that the event emitter seems to be "emitting" the action two times, despite the fact that I am only calling the action once (onClick).

Component


    var TodoHead = React.createClass({
        addItem: function(e){

            var todo = this.refs.TodoInput.getDOMNode().value;
            TodoActions.addTodoItem(todo);

            // signal that there was a change to the todo object/array
            TodoActions.todoItemsChanged();
        },
        removeItem: function(){

            TodoActions.removeItem(); 

            TodoActions.todoItemsChanged();
        },
        render: function(){

            return (
                // buttons that triggers the methods above onClick 
            );
        }
    });

Reflux store


    var todoItems = [];
    var API = {
        addTodoItem: function(item){
            debugger;
            if(item != ""){
            todoItems.push(item);
            }
        },
        removeTodoItem: function(){

            todoItems.pop();
        },
    }

    var TodoStore = Reflux.createStore({
        init: function(){
            this.listenTo(TodoActions.addTodoItem,API.addTodoItem);
            this.listenTo(TodoActions.removeItem,API.removeTodoItem);
        },
        getTodos: function(){

            return todoItems;
        },
    });

Reflux Actions


    var TodoActions = Reflux.createActions([
        'addTodoItem',
        'removeItem',
        'todoItemsChanged'
    ]);

As you can imagine, this has been a real thorn in my side. What am I doing wrong?

Any answers will be appreciated!!

1
Can you add a jsfiddle of the problem? - WiredPrairie

1 Answers

1
votes

You shouldn't need TodoActions.todoItemsChanged().

How it should work is you just call TodoActions.addTodoItem(todo).

So, no todoItemsChanged action.

The Store listens to the Action. The Component listens to the Store. The Component calls Actions.

So, Action->Store->Component->Action and so on.

The store listens to the Action and does stuff, and then triggers a change:

var TodoStore = Reflux.createStore({
    init: function(){
        this.listenTo(TodoActions.addTodoItem,this.addTodoItem);
        this.listenTo(TodoActions.removeItem,this.removeTodoItem);
    },
    getInitialState() {
      this.todos = []; // or whatever
      return this.todos;
    },
    addTodoItem(todo) {
      API.addTodoItem(todo);
      // There are no hard and fast rules here,
      // you can do this however you want
      this.update([todo].concat(this.todos));
    },
    removeTodoItem() {
      // Similar to the above
    },
    // The docs do use this method
    // but you can call this.trigger from the liteners
    update(todos) {
      this.todos = todos;
      this.trigger(todos);
    },
});

You might need to adjust your API to fit this format. The Store should store the actual todos and call out to the API. The method above updates the local state without checking to see if the API succeeds. I call out to my api and use callbacks like this (Api uses superagent behind the scenes):

// Actual code I pulled for a project I'm working on
onAddNote(id, note) {
  Api.createNote(id, note, (err, res) => {
    let lead = JSON.parse(res.text).lead;
    this.updateLead(lead);
  })
},

Components listen to changes on the store (and call Actions, which you already have):

var TodoStore = require('/path/to/TodoStore');
var Reflux = require('reflux');

var TodoHead = React.createClass({
  mixins: [Reflux.connect(TodoStore, 'todos')],
  // **insert the rest of your component**
  // this will add the current value of
  // of the todos onto the state, you
  // access it at this.state.todos

Every time the store calls this.trigger(this.todos), the state of your component will be updated thanks the the Mixin.

There are other ways to connect to the store, see The Reflux Docs.