Skip to content Skip to sidebar Skip to footer

Reactjs - Have A "main" Component That Doesn't Own It's Children?

I've got a bunch of components that can't have the same parent component, but I'd like them to share their state. For discussions sake, lets say the top level component is called

Solution 1:

Rather than directly calling setState you can use an event emitter, and all of the instances can apply the payload to their state.

We can use a mixin to abstract this behavior.

var makeChangeEventMixin = function(emitter){
   return {
       componentDidMount: function(){
           emitter.addListener('change', this.__makeChangeEventMixin_handler_);
       },
       componentWillUnmount: function(){
           emitter.removeListener('change', this.__makeChangeEventMixin_handler_);
       },
       __makeChangeEventMixin_handler_: function(payload){
           this.setState(payload);
       },
       emitStateChange: function(payload){
           emitter.emit('change', payload);
       }
   };
};

Then in our code we'll use EventEmitter (you can use EventEmitter2 if you're not using browserify/webpack)

varEventEmitter = require('events').EventEmitter;
var fooEvents = newEventEmitter();

varCounter = React.createClass(){
    mixins: [makeChangeEventMixin(fooEvents)],
    getInitialState: function(){ return {count: 0} },
    render: function(){return<divonClick={this.handleClick}>{this.state.count}</div>},
    handleClick: function(){
        this.emitStateChange({count: this.state.count + 1});
    }
};

And if you have 100 counters, they'll all update when you click any of them.


One limitation of this is that the initial state will be wrong. You could work around this by keeping track of the state in makeChangeEventMixin, merging it your self, and using replaceState in stead of setState. This'll also be more performant. If you do that, the mixin can implement a proper getInitialState.

Solution 2:

One component of mine called ItemRenderer calls renderComponent in three places in the DOM on mount and on each update (and renders just an empty div into its real container):

https://github.com/Khan/perseus/blob/a1811f6b7a/src/item-renderer.jsx#L66-L130

This tends to be a little bit hard to reason about because the components don't go where ItemRenderer's parent tells them to, but it can work if that's what you need.

Post a Comment for "Reactjs - Have A "main" Component That Doesn't Own It's Children?"