0

I'm trying to determine when at least one checkbox is checked in React.

I have a Checkbox component:

import * as React from 'react';
import * as DOM from 'react-dom';
import PropTypes from 'prop-types';

class Checkbox extends React.Component {
  constructor(props) {
        super(props);
  }

    render() {
      return(
        <div>
        <label>
        <input 
      type="checkbox" 
      name={this.props.value} 
      value={this.props.value} 
      onClick={this.props.function}
      />
    <span>
      <span>
        {this.props.title}
      </span>
    </span>
  </label>
  </div>
      );
    }
}

Checkbox.PropTypes = {
  title: PropTypes.string,
  value: PropTypes.string,
  function: PropTypes.func,
}

export default NewsletterCheckbox;

It is imported and used in a parent component:

  checkFields() {
    // check if other fields are not empty and valid
    console.log(this.state);
  }
  isCheckboxChecked(event) {
    // determine if at least one checkbox is checked, and if so
    // update state
    const checkboxes = document.querySelectorAll('input[type="checkbox"]');
    const checkedOne = Array.prototype.slice.call(checkboxes).some(x => x.checked);
    if (checkedOne) {
      this.setState({ checkboxValid: true }, this.checkFields);
    } else {
      this.setState({ checkboxValid: false }, this.checkFields);
    }
  }     
  const newsletterArray = NewsletterData.map((obj) => (
    <div key={obj.value}>
      <div>
      <Checkbox
        value={obj.value}
        title={obj.title}
        function={this.isCheckboxChecked}
        />
      </div>
      <p>
          {obj.body}
          <br />
        <a onClick={(e) =>  {this.handleModal(e) }} data-iframe={obj.link}>
            See Preview
          </a>
        </p>
    </div>
  ));

The issue I'm running in to is that the function that runs when any of the checkboxes are checked, isCheckboxChecked(), once one field has been checked, if I uncheck that field (or check a bunch, and then uncheck them all), it never comes back as false.

Is there a better way of checking if at least one checkbox is checked in React without querying the DOM (which doesn't seem to work correctly with React rendered checkboxes)?

3
  • Don't query the DOM. Keep an array in the parent's state to store the state of your checkboxes. That state is passed down to each Checkbox, and the function you pass down will change the parent's state array. This way you can read the state of the checkboxes at any time. Commented Jan 31, 2020 at 10:54
  • You should probably implement onChange and keep the state of the checkbox in the parent component. This way you'll be able to check whether the selected ones meet you criteria. In React you should almost never resort to querying the DOM, and if had to, you would use ref not direct DOM queries. Commented Jan 31, 2020 at 10:54
  • Here's how I do this: codesandbox.io/s/cool-banach-rm7qd Commented Jan 31, 2020 at 12:38

1 Answer 1

1

You should keep a counter of the checked checkbox

  <input 
    type="checkbox" 
    name={this.props.value} 
    value={this.props.value} 
    onChange={this.props.onChange} />
constructor(props) {
  super(props);
  this.state = {checkCount: 0}
}

<Checkbox
   value={obj.value}
   title={obj.title}
   onChange={(e) => {
     if (e.target.checked)
       this.setState((prevState) => ({checkCount: prevState.checkCount + 1, checkboxValid: true}))
     else {
       this.setState((prevState) => ({checkCount: prevState.checkCount - 1}), () => {
         if (this.state.checkCount === 0)
           this.setState({checkboxValid: false})
       })
     }
   }} />

We are setting the checkCount to +1 or -1 if the user checks or unchecks the checkbox. If he unchecks it, after updating the checkCount, we need to verify this.state.checkCount === 0 in order to set the checkboxValid state to false if the condition is valid.

Sign up to request clarification or add additional context in comments.

2 Comments

The first condtion on the onChange handler throws an error. I'm assuming it needs to be wrapped in the arrow func like the one in the else condition? Either way, neither of these seem to update the state of either values (checkCount or checkboxValid).
I edited the answer (forgot some () : {checkCount: prevState.checkCount - 1} => ({checkCount: prevState.checkCount - 1})). You can check the live version here : codesandbox.io/s/angry-aryabhata-ub2qn

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.