Checkboxes in React

In React, data flows unidirectionally. This means that the State becomes the source of truth – especially working with controlled components and forms.

Having said that, you will see your form HTML riddled with something like:

<input type="text" value={this.state.value} onChange={this.handleChange} />

And in your class, something like:

handleChange(event) {
  this.setState({value: event.target.value});
}

This is to enforce this unidirectional pattern, making the state mutable and can only be changed with “setState”.

This is fine I and all, but working with checkboxes isn’t that straightforward. That’s why I decided to write about it – so I won’t forget.

The Requirement: A very typical scenario is loading a form, with some values preloaded on the fields. So when the user changes the value – it updates the data in the backend.

So let’s build that the “natural” React way:

class User extends Component { 

  constructor(props) {
    super(props);
    this.state = {
        receiveEmails : '', 
        shareMyInfo : '', 
    }

  } //end constructor

} //end class

Above we start with standard boilerplate class with a constructor. I have 2 checkboxes (not an array of checkboxes – but 2 separate checkboxes with different names), so I set them up in my initial state.

In the HTML (or render), I add the markup:

 render() { 
    return (
    <form>
    Receive Email:
    <input type="checkbox" onChange={this.handleCkboxChange} 
        name="receiveEmails" />
    <hr />
    Share My Info:
    <input type="checkbox" onChange={this.handleCkboxChange} 
        name="shareMyInfo" />    
    </form>
    )
 }

I don’t have a “value” for them because all I need is to send 1 or 0 – as in checked or not. Again, its not the array of checkboxes where its different values stuffed in an array. But I’m sure its going to be the same concept.

You see our “handleCkboxChange” handler, which should have our state change (using setState()). So let’s do that.

But wait, to grab if our checkbox is “checked” or not, we have to use refs. Let’s define that in our constructor:

this.receiveEmailsCkbox = React.createRef();
this.shareMyInfoCkbox = React.createRef();

Now we can use this in our handler like so:

handleCkboxChange(event){   
    let refName = event.target.name + "Ckbox";
    let node = this[refName].current;
    let key = event.target.name;
    let obj = {};

    obj[key] = node.checked ? "1" : "";

    this.setState(obj);
  }

You see, we created a generic handler for our check boxes – so we can’t rely on simply grabbing the “event”. We have to concatenate the name to match the refs we created in our constructor. Then we have access to the actual HTML node to see if it’s checked or not.

Finally we update our state with “setState“.

So that’s fine, this works and updates our state. Now to fulfill our requirement above, we have to load our check boxes with a default value. Let’s introduce the life cycle hook called componentDidMount() and stuff new state in there.

componentDidMount (){     
    setTimeout(function(){
       this.setState({
           receiveEmails : '1', 
           shareMyInfo : '',
       })
    },1000)
}

The componentDidMount() method is a point in time where our markup is added to the page. Its a good spot to do AJAX and call the backend. In our example, we’re simply using setTimeout() for illustration. So you see one should be checked and one isn’t.

So just like in regular HTML, we need to add a “checked” attribute to our checkboxes. Note that we cannot use the “defaultChecked” attribute, because when initialized (in our constructor), the values are empty. So our checkboxes will showup unchecked. So we use the regular “checked“:

 <input type="checkbox"
      defaultChecked={this.state.receiveEmails === "1" ? true : false}
      onChange={this.handleCkboxChange}
      name="receiveEmails"
        />

And there you go, now we have met our requirement of having the checkboxes load with values from our backend, and still kept the React way of doing things.

Checking and unchecking the boxes updates our state – just like it should. If you would like to see the running code, check it out in Codesandbox. Leave your comments below.

Leave a Comment.