1

I'm trying to put all checked checkboxes in the state array. I am able to add values to the array, but I cannot delete the value when I uncheck the box. I've tried using splice and delete by index, also tried deleting through a filter. It works, but it works slowly and incorrectly. For example I can uncheck all the checkboxes and one value stay in the state. Please check what I'm doing wrong Here is a Sandbox link and my code below

const [state, setState] = useState({
    address: [],
  })

  const checkboxChange = (e) => {
    const { name, checked } = e.target
    if (checked === true) {
      setState((prevState) => ({
        ...prevState,
        address: [...prevState.address, name],
      }))
    }
    if (checked === false) {
      setState((prevState) => ({
        ...prevState,
        address: [...prevState.address].filter((it) => it.id !== it.id),
      }))
    }
  }
{list.map((it, index) => (
        <div key={it.id}>
          <label>
            <input
              className="mr-2"
              checked={state.address.index}
              key={it.id}
              name={it.id}
              defaultValue="false"
              onChange={checkboxChange}
              type="checkbox"
            />
            {it.name}
          </label>
        </div>
      ))}
2
  • You have uncontrolled inputs and it.id !== it.id will always evaluate false`. Why are you storing checked state in an array? Commented Nov 1, 2020 at 22:07
  • It looks like you got your answer, but FYI you should never use splice on a react state because it mutates the array. Commented Nov 1, 2020 at 22:24

1 Answer 1

5

Issue

You are comparing it.id !== it.id which will always evaluate to false.

Solution

state.address is an array of the ids, not objects with an id property, and you want to compare each one against the input's name in the onChange event object.

  1. Just filter prevState.address
  2. Compare el !== name

Code

const checkboxChange = (e) => {
  const { name, checked } = e.target;

  if (checked) {
    setState((prevState) => ({
      ...prevState,
      address: [...prevState.address, name],
    }))
  } else {
    setState((prevState) => ({
      ...prevState,
      address: prevState.address.filter((el) => el !== name),
    }))
  }
}

Edit controlled-checkbox-in-react

Controlled Inputs

If you really want your inputs to be controlled then I suggest:

  1. Store the checked values in a map
  2. Simply toggle the checked values from onChange event
  3. Use the value attribute versus the defaultValue attribute of the input

Code

const App = (props) => {
  const [state, setState] = useState({
    address: {}, // <-- object map
  })

  useEffect(() => {
    console.log(state)
  }, [state])

  const checkboxChange = (e) => {
    const { name } = e.target
    setState((prevState) => ({
      ...prevState,
      address: {
        ...prevState.address,
        [name]: !prevState.address[name], // <-- toggle state
      },
    }))
  }

  return (
    <div>
      {list.map((it, index) => (
        <div key={it.id}>
          <label>
            <input
              className="mr-2"
              checked={state.address.index}
              key={it.id}
              name={it.id}
              value={state.address[it.id]} // <-- set from checked state
              onChange={checkboxChange}
              type="checkbox"
            />
            {it.name}
          </label>
        </div>
      ))}
    </div>
  )
}

Edit controlled-checkbox-in-react (forked)

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

2 Comments

[name]: !prevState.address[name]? is a boolean value, so it wouldn't have the checked property
@ZacharyHaber Thanks for catching my copy/paste bug, though it still technically worked, it should have been value={state.address[it.id].checked} :p. Updated both snippet and sandbox.

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.