4

Take e.g. the Flux TodoMVC and suppose I want to have two Todo-Apps next to each other.

class TwoTodos extends React.Component {
  render () {
    return (
      <div>
        <TodoApp />
        <TodoApp />
      </div>
    );
  }
}

Now, when you run this example you will notice that both Todo-lists will be synchronized as both emit and listen to the same actions.

What is the canonical way to prevent this?

Aton
  • 1,125
  • 8
  • 18
  • 1
    It's working as expected. You'd need to change the design ... for example, the store would need to have more information about the source of the data (like an identifier associated with each instance). – WiredPrairie Mar 20 '15 at 16:59
  • Not sure about what I'm saying...but worth a try. Add a key attribute to the TodoApp elements: – ema Mar 20 '15 at 17:11
  • You can either pass around an appID like @WiredPrairie mentioned and then nest the data structures in the stores under that appID, or you can use store and dispatcher instances and pass those instances around as needed -- up to you how you think this would work best for your application. With the instances approach, any component that calls an action creator would need a reference to the dispatcher, and it would pass the dispatcher to the action creator. – fisherwebdev Mar 20 '15 at 20:25

1 Answers1

0

I just solved this issue. It took me a couple of days to figure it out.

In general, you should make your action and store to be classes, instead of normal objects that can be shared among Todo components. And then create an instance of the action class and store class in every Todo Component.

To avoid components affect each other, you need to encapsulate the public variables that can be shared by different component instances, like _todos in the TodoStore.js, into your store class.

Then you need to wrap what is rendered in the app.js into a class, and create instances of this class before it is used.

I'll put the key changes in the code below.

TodoActions.js:

var Actions = function(){
    //if you have any shared variables, just define them here, instead of outside of the class 

    this.getAction = function(){
        return TodoActions;
    } 
    var TodoActions = {...};
    ...
}
module.exports = Actions;

TodoStore.js:

//private functions
function create(text, todos){...}
function update(id, updates, todos){...}

var Store = function(){
    var _todos = {};
    this.getStore = function(){
        return TodoStore;
    }   

    var TodoStore = assign({}, EventEmitter.prototype, {...});
};
module.exports = Store;

TodoApp.react.js:

var TodoApp = React.createClass({
    Store: function(){},
    Actions: function(){},
    componentWillMount: function(){
        var store = require('path/to/TodoStore.js');
        var storeInstance = new store();
        this.Store = storeInstance.getStore();  

        var action = require('path/to/TodoActions.js');
        var actionInstance = new action();
        this.Store = actionInstance .getAction();  

        this.Store.addChangeListener(...);
    }
    //If you need to call methods in Actions, just call this.Actions.<method_name>
});    
module.exports = TodoApp;

app.js:

var TodoApp = require('./components/TodoApp.react');
window.Todo = function(){
    var todo = null; //In case you need to get/set the component
    this.use = function(elementId){
        todo = ReactDom.render(
            <TodoApp />,
            document.getElementById(elementId)
        )
    }
};

index.html:

<section id="todoapp1"></section>
<section id="todoapp2"></section>
<script>
    var todo1 = new Todo();
    var todo2 = new Todo();
    todo1.use('todoapp1');
    todo2.use('todoapp2');
</script>
shaosh
  • 657
  • 2
  • 8
  • 30