Home  >  Q&A  >  body text

Uncheck multiple checkboxes in checkbox group using React hooks

<p>I ran several checkboxes in several checkbox groups. I can't figure out how to uncheck (thereby changing the state) a specific checkbox. For some reason I can't access <code>e.target.checked</code>. </p> <pre class="brush:php;toolbar:false;"><Checkbox size="small" name={item} value={item} checked={checkboxvalues.includes(item)} onChange={(e) => handleOnChange(e)} /></pre> <p>and my functions</p> <pre class="brush:php;toolbar:false;">const handleOnChange = (e) => { const check = e.target.checked; setChecked(!check); };</pre> <p>I made a working example of the component in <strong>this sandbox</strong>. </p>
P粉008829791P粉008829791438 days ago450

reply all(2)I'll reply

  • P粉322319601

    P粉3223196012023-08-31 09:00:43

    Here's how I did it: https://codesandbox.io/s/elastic-pateu-flwqvp?file=/components/Selectors.js

    I abstracted the selection logic into a useSelection() custom hook, which means the current selection can be found in store[key].selected, where key can be any key of selectors.

    items, selected, setSelected and sectionLabel are stored in each useSelection() call In store[key], and passed to a <CustomCheckboxGroup /> component.

    The relevant part is the handleCheck function within this component, which sets the new selection based on the previously selected value: if the current item is contained within the previously selected value, remove it. Otherwise, add it.


    More detailed explanation (why)

    Looking closely at your code, it seems like you are confused about how the checkbox component works in React.

    The

    checked attribute of input is controlled by a boolean state. Generic example:

    const Checkbox = ({ label }) => {
      const [checked, setChecked] = useState(false)
      return (
        <label>
          <input
            type="checkbox"
            checked={checked}
            onChange={() => setChecked(!checked)}
          />
          <span>{label}</span>
        </label>
      )
    }
    

    On each render, the checked value of <input /> is set based on the current value of the checked state. When the entered checked changes (during user interaction), the status is not automatically updated. But the onChange event is fired and we use it to update the state to the negative value of the state's previous value.


    When dealing with the <CheckboxList /> component, we cannot use a single boolean value to control all checkboxes , we need to set a boolean value for each checkbox being rendered. So we create a selected array and set the checked value of each <input /> to selected.includes(item) The value of (returns a boolean).

    In order for this to work, we need to update the value of the

    selected array in every onChange event. We check if item is contained in the previous version of selected. If present, filter it out. If it doesn't exist, add it:

    const CheckboxList = ({ items }) => {
      const [selected, setSelected] = useState([])
      const onChecked = (item) =>
        setSelected((prev) =>
          prev.includes(item)
            ? prev.filter((val) => val !== item)
            : [...prev, item]
        )
    
      return items.map((item) => (
        <label key={item}>
          <input
            type="checkbox"
            checked={selected.includes(item)}
            onChange={() => onChecked(item)}
          />
          <span>{item}</span>
        </label>
      ))
    }
    

    Hope this solves some problems.

    reply
    0
  • P粉060528326

    P粉0605283262023-08-31 00:36:19

    You need to create specific handleOnChange function for each group. I have created a similar function for the Genre checkbox group and you can create it for other groups in the same way.

    This is the processing function.

    const handleOnChangeGenre = (e) => {
        let newValArr = [];
        if (e.target.checked) {
          newValArr = [...state.pillarGenre.split(","), e.target.value];
        } else {
          newValArr = state.pillarGenre
            .split(",")
            .filter((theGenre) => theGenre.trim() !== e.target.value);
        }
        setState({ ...state, pillarGenre: newValArr.join(",") });
      };

    Pass this function to CustomCheckboxGroup as the handleOnChange attribute as shown below.

    <CustomCheckboxGroup
              checkboxdata={genres}
              checkboxvalues={state.pillarGenre}
              value={state.pillarGenre}
              sectionlabel="Genre"
              onToggleChange={handleGenreSwitch}
              togglechecked={genreswitch}
              handleOnChange={handleOnChangeGenre}
            />

    For testing, comment out your handleOnChange function.

    See the complete working solution in the sandbox - Complete code

    reply
    0
  • Cancelreply