Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

reactjs

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.

like image 651
SuperFLEB Avatar asked Dec 18 '15 18:12

SuperFLEB


People also ask

What happens when a state is changed in React?

React components has a built-in state object. The state object is where you store property values that belongs to the component. When the state object changes, the component re-renders.

How do you update state of parent component from a child component in React?

To update the parent state from the children component, either we can use additional dependencies like Redux or we can use this simple method of passing the state of the parent to the children and handling it accordingly.


2 Answers

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>
    );
  }
});
like image 118
Haizi Avatar answered Oct 12 '22 15:10

Haizi


You change it from only the parent.

class ParentComponent extends React.Component{
  handleChildCheck(){
    this.setState({
     childChecked: !this.state.childChecked
    })
  }
  render(){
    return(
      <ChildComponent checked={this.state.childChecked} handleCheck={this.handleChildCheck.bind(this)} />
    )
 }
}

Now if you wish to control the checked state from the <ChildComponent/> just call this.props.handleCheck() from the <ChildComponent/>

This way the controls will always be available within the <ChildComponent/> via this.props.handleCheck() within the <ParentComponent/> via this.handleChildCheck().

like image 3
Naisheel Verdhan Avatar answered Oct 12 '22 16:10

Naisheel Verdhan