5 min read

You can get a long way in React.js solely by having parent components create child components with varying props, and having each component deal only with its own state. But what happens when a child wants to affect its parent’s state or props? Or when a child wants to inspect that parent’s state or props? Or when a parent wants to inspect its child’s state?

With the right techniques, you can handle communication between React components without introducing unnecessary coupling.

Child Elements Altering Parents

Suppose you have a list of buttons, and when you click one, a label elsewhere on the page updates to reflect which button was most recently clicked. Although any button’s click handler can alter that button’s state, the handler has no intrinsic knowledge of the label that we need to update. So how can we give it access to do what we need?

The idiomatic approach is to pass a function through props. Like so:

var ExampleParent = React.createClass({

getInitialState: function() {

return {lastLabelClicked: "none"}

},

render: function() {

var me = this;

var setLastLabel = function(label) {

me.setState({lastLabelClicked: label});

};

return <div>

<p>Last clicked: {this.state.lastLabelClicked}</p>

<LabeledButton label="Alpha Button" setLastLabel={setLastLabel}/>

<LabeledButton label="Beta Button" setLastLabel={setLastLabel}/>

<LabeledButton label="Delta Button" setLastLabel={setLastLabel}/>

</div>;

}

});

var LabeledButton = React.createClass({

handleClick: function() {

this.props.setLastLabel(this.props.label);

},

render: function() {

return <button onClick={this.handleClick}>{this.props.label}</button>;

}

});

Note that this does not actually affect the label’s state directly; rather, it affects the parent component’s state, and doing so will cause the parent to re-render the label as appropriate.

What if we wanted to avoid using state here, and instead modify the parent’s props?

Since props are externally specified, this would be a lot of extra work. Rather than telling the parent to change, the child would necessarily have to tell its parent’s parent—its grandparent, in other words—to change that grandparent’s child. This is not a route worth pursuing; besides being less idiomatic, there is no real benefit to changing the parent’s props when you could change its state instead.

Inspecting Props

Once created, the only way for a child’s props to “change” is for the child to be recreated when the parent’s render method is called again. This helpfully guarantees that the parent’s render method has all the information needed to determine the child’s props—not only in the present, but for the indefinite future as well.

Thus if another of the parent’s methods needs to know the child’s props, like for example a click handler, it’s simply a matter of making sure that data is available outside the parent’s render method. An easy way to do this is to record it in the parent’s state:

var ExampleComponent = React.createClass({

handleClick: function() {

var buttonStatus = this.state.buttonStatus;

// ...do something based on buttonStatus

},

render: function() {

// Pretend it took some effort to determine this value

var buttonStatus = "btn-disabled";

this.setState({buttonStatus: buttonStatus});

return <button className={buttonStatus} onClick={this.handleClick}>

Click this button!

</button>;

}

});

It’s even easier to let a child know about its parent’s props: simply have the parent pass along whatever information is necessary when it creates the child. It’s cleaner to pass along only what the child needs to know, but if all else fails you can go as far as to pass in the parent’s entire set of props:

var ParentComponent = React.createClass({

render: function() {

return <ChildComponent parentProps={this.props} />;

}

});

Inspecting State

State is trickier to inspect, because it can change on the fly. But is it ever strictly necessary for components to inspect each other’s states, or might there be a universal workaround?

Suppose you have a child whose click handler cares about its parent’s state. Is there any way we could refactor things such that the child could always know that value, without having to ask the parent directly?

Absolutely! Simply have the parent pass the current value of its state to the child as a prop. Whenever the parent’s state changes, it will re-run its render method, so the child (including its click handler) will automatically be recreated with the new prop. Now the child’s click handler will always have an up-to-date knowledge of the parent’s state, just as we wanted.

Suppose instead that we have a parent that cares about its child’s state. As we saw earlier with the buttons-and-labels example, children can affect their parent’s states, so we can use that technique again here to refactor our way into a solution.

Simply include in the child’s props a function that updates the parent’s state, and have the child incorporate that function into its relevant state changes. With the child thus keeping the parent’s state up to speed on relevant changes to the child’s state, the parent can obtain whatever information it needed simply by inspecting its own state.

Takeaways

Idiomatic communication between parent and child components can be easily accomplished by passing state-altering functions through props. When it comes to inspecting props and state, a combination of passing props on a need-to-know basis and refactoring state changes can ensure the relevant parties have all the information they need, whenever they need it.


About the Author

Richard Feldman is a functional programmer who specializes in pushing the limits of browser-based UIs. He’s built a framework that performantly renders hundreds of thousands of shapes in HTML5 canvas, a writing web app that functions like a desktop app in the absence of an Internet connection, and much more in between.

LEAVE A REPLY

Please enter your comment!
Please enter your name here