ReactJS - is there a "main" component that doesn't own its children?

I have a bunch of components that cannot have the same parent component, but I would like them to share their state.

For the sake of discussion, let's say the top-level component is named Main

, and all the children are named Child1

, Child2

etc.

Do I have a way to have Child1

and Child2

child elements Main

, only in the sense of the React, so I can pass the property Main

and point to them from Main

the component?

In terms of the DOM, Child1

both Child2

are located in completely different areas of my page, and there are actually about 40 of them.

+2


source to share


2 answers


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

We can use a mixin for abstract 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 will use EventEmitter (you can use EventEmitter2 if you are not using browser / webpack)



var EventEmitter = require('events').EventEmitter;
var fooEvents = new EventEmitter();

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

      

And if you have 100 counters, they will update when you click any of them.


One limitation of this is that the initial state will be wrong. You can work around this by tracking the state in makeChangeEventMixin, concatenating it yourself and using replaceState instead of setState. It will also be more effective. If you do this, the mixin can implement the correct getInitialState.

+1


source


One of my components, called ItemRenderer, calls renderComponent at three places in the DOM on mount and every update (and only renders an empty div to its real container):

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



This is usually a little tricky to reason about because components don't go where the parent ItemRenderer points them, but it might work if you need to.

+1


source







All Articles