0

I want to change the value of a checkbox and get its value.

with:

const[check, setCheck] = useState()

  const handleChange = () =>{
    setCheck(prevValue => !prevValue)
    console.log(check)
  }

it works fine, it shows true and false by clicking

with:


 const [checked, setChecked] = useState({
     checked1: false,
     chekced2: false, 
    ...
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setChecked((prevState) => {
      return {
        ...prevState,        
        [name]: value
      };
    });    
    console.log(checked.checked1)    
  };

it only shows false only, if it is checked or not. Where is my mistake?

Spluli
  • 59
  • 6
  • See https://stackoverflow.com/questions/54069253/the-usestate-set-method-is-not-reflecting-a-change-immediately?rq=1 – Nice Books Sep 09 '22 at 16:09

1 Answers1

1

This partly is because you are logging immediately after the set state. React does not immediately update the value, its flushed later at the end of the call stack and becomes what you expect on the next rerender.

More info: https://beta.reactjs.org/apis/react/useState#ive-updated-the-state-but-logging-gives-me-the-old-value

What you need to do depends on if the <input> is controlled or not. Its controlled if you pass the checked prop to it and uncontrolled if you do not pass it.

For controlled use:


  // You also need to ensure your default state has all the
  //names of each checkbox rendered from the beginning and they are 
  // set to false. THIS IS CRUCIAL IN THIS PATTERN! 
  // Or e.target.checked would be undefined.
  // e.g.
  //
  // const [checked, setChecked] = useState({
  //     name1: false,
  //     name2: false,
  //     name3: false,
  //     ... // etc
  // })

  const handleChange = (e) => {
    const { name, checked} = e.target;
    setChecked((prevState) => {
      return {
        ...prevState,        
        [name]: checked
      };
    });       
  };

 // Input must be bound like
 // <input name="your-name" onChange={handleChange} checked={this.state.checked["your-name"]} />
 

For uncontrolled use:

  const handleClick = () => {
    const { name } = e.target;
    setChecked((prevState) => {
      return {
        ...prevState,        
        [name]: !Boolean(prevState[name])
      };
    });       
  };

 // Input must be bound like
 // <input name="your-name" onClick={handleChange} defaultChecked={false} />

adsy
  • 8,531
  • 2
  • 20
  • 31
  • When i replace my code with yours, it says "undefined" instead of "false". I read, that articel in the link - but i cant derive how to implement it in my code – Spluli Sep 12 '22 at 10:15
  • And thats also with the logging in render and *not* after the setState call? Also, is this checkbox just a base html checkbox or one from another library? – adsy Sep 13 '22 at 14:44
  • My guess is that your checkbox has controlled state. Do you set `checked` on the `input`? If so, instead use `onClick` and not `onChange` and base the new value on the not of the previous one – adsy Sep 13 '22 at 14:47
  • I have edited with a clearer explanation – adsy Sep 13 '22 at 14:52
  • My guess is you arae probably use onChange (controlled pattern) but possible forgot to either/both (a) Ensure that the checked state object has all the names in it on first render and they are set to false and (b) Ensured that `checked` is bound. – adsy Sep 13 '22 at 14:54
  • its easy to fall in this trap by thinking you are all good since `checked` prop is set set on the JSX, but if thats undefined on first render, it will blow up. It needs to be known to be false so the state item needs them all in from the beginning with it set to false and not undefined. If its undefined at any point, it will blow up in the way you are seeing – adsy Sep 13 '22 at 14:56