martyjs / marty

A Javascript library for state management in React applications
http://martyjs.org
MIT License
1.09k stars 76 forks source link

Two Marty State Mixins cause onStoreChanged invariant violation #102

Closed dariocravero closed 9 years ago

dariocravero commented 9 years ago

Hi all,

I'm trying to figure out as to whether this is: a) properly done :), b) a Marty issue or a c) React issue.

How do you deal with two State Mixins pulling state from different stores and trying to be mixed into the same view?

Here's a gist showcasing the issue.

Given two StateMixins:

var EditableState   = Marty.createStateMixin({
  listenTo: EditableStore,

  getState: function() {
    return {
      editable: EditableStore.isEditable()
    };
  }
});
var BlockState = Marty.createStateMixin({
  listenTo: BlockStore,

  getState: function() {
    return {
      block: BlockStore.getBlock(this.props.blockId)
    };
  }
});

And a view that uses them:

var View = React.createClass({
  mixins: [
    BlockState,
    EditableState
  ],

  render: function() {
    return <div>A view</div>;
  }
});

The view fails with Uncaught Error: Invariant Violation: ReactCompositeComponentInterface: You are attempting to defineonStoreChangedon your component more than once. This conflict may be due to a mixin..

Is this the wrong approach? Or maybe it's a Marty or a React issue?

When Googling the symptoms I found this facebook/react#375 but it's not strictly related, plus there are no Policys being enforced in for onStoreChanged unless it's a default?

Thanks! Darío

dariocravero commented 9 years ago

After this simplified example, I think this is either a bad practice or a React issue. facebook/react#3027

jhollingworth commented 9 years ago

Hey, StateMixin's can listen to multiple stores

var ViewState = Marty.createStateMixin({
  listenTo: [EditableStore, BlockStore],

  getState: function() {
    return {
      editable: EditableStore.isEditable(),
      block: BlockStore.getBlock(this.props.blockId)
    };
  }
});
var View = React.createClass({
  mixins: [ViewState],
  render: function() {
    return <div>A view</div>;
  }
});
dariocravero commented 9 years ago

I wanted to make the editable listener a reusable mixin because it will be used throughout many views that may or may not share the same mixin but in all fairness the overload isn't that big and it probably makes sense to do that... :) Thanks