How do I manage state on a React component that can have state changed from the parent or from events upon it?

- 1 answer

Ad

I'm trying to make a custom checkbox component (a three-state, actually, but that's irrelevant except to say that I'm not just using an INPUT), and I'm not sure how I can make it able to change "checkedness" from clicks on itself and from a value-set coming down from the parent.

Currently, I have it working as a self-sufficient component that takes an onChange prop with the handler callback that it calls to send the value the parent component after clicks. It uses a state to store the checkedness, which is referenced by the display.

If it were merely a display of checkedness, with value being managed from outside, I'd use props, naturally. If it were only a self-sufficient checkbox component that took an initial value then only responded to clicks, I'd use state, like I am, but my problem is that I want it to be clickable to turn itself on and off, and allow the parent to turn it on and off as well.

I'm a beginner to React and the "React way of thinking" so I suspect I'm just approaching this wrong. I kind of get the impression that the proper way to do this would be for it to be a display-only component that passed clicks up to the parent to deal with, and in turn received props updates for value changes down from the parent, but that would make the component far less reusable, to my mind.

So how would I go about making a checkbox change from both internal and parent sources?

Relevant links are welcome, as well.

Ad

Answer

Ad

You may treat the checkbox as a dumb component, which means that it doesn't hold any internal states, but only receives data from outside via props and then render them. You can see the detailed definition of dumb components here.

Meanwhile, when the checkbox is clicked, such event will be handled by the component's parent, or event ancestors, this is called inverse data flow, which is described in Facebook's Thinking in React blog post.

Moreover, to decide which component should hold certain states, I find the following guidelines very useful:

Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:

For each piece of state in your application:

  • Identify every component that renders something based on that state.
  • Find a common owner component (a single component above all the components that need the state in the hierarchy).
  • Either the common owner or another component higher up in the hierarchy should own the state.
  • If you can't find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component.

The pseudo-code snippet:

const Checkbox = React.createClass({
  // Propagate the event to parents
  onClick(evt) {
    if (this.props.handleClick) {
      this.props.handleClick({checked: evt.target.value});
    }
  },

  render() {
    return (
      this.props.checked ? 
        <Input onClick={this.onClick} type="checkbox" label="Checkbox" checked></Input> : 
        <Input onClick={this.onClick} type="checkbox" label="Checkbox"></Input>
    );
  }
});

const Container = React.createClass({
  handleClick(evt) {
    // Change the container's state, which eventually changes the checkbox's view via props.
    this.setState({checked: evt.checked});
  },

  render() {
    return (
      <div><Checkbox checked={this.state.checked} handleClick={this.handleClick}></Checkbox></div>
    );
  }
});
Ad
source: stackoverflow.com
Ad