3

I have a quite simple question. Can me someone tell, why the status of the checkboxes doesn't change? The booleans in check change, but not the status of the checkboxes.

function KP() {
  const [name] = useState(["1", "2"]);
  const [check, setCheck] = useState([true, false]);

  const handleChange = (event) => {
    const { id, checked } = event.target;
    const index = name.indexOf(id);
    var temp = check;
    temp[index] = checked;
    setCheck(temp);
  };

  return (
    <div>
      {name.map((n, index) => {
        return (
          <div>
            <p>{n}</p>
            <input type="checkbox" checked={check[index]} onChange={handleChange} id={n} key={n}/>
          </div>
        );
      })}

    </div>
  );
}
lomu98
  • 55
  • 7

4 Answers4

2

Because you're using the same reference(var temp = check;) to update state(check).

Try this

const handleChange = (event) => {
    const { id, checked } = event.target;
    const index = name.indexOf(id);
    check[index] = checked;
    setCheck([...check]);
};

Demo link here

Naren
  • 4,152
  • 3
  • 17
  • 28
  • It works. I thought you couldn't change constants. Can you explain to me what the three dots in front of the constant mean? – lomu98 Jan 10 '21 at 14:09
  • 1
    It's called [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax), is a useful and quick syntax for adding items to arrays, combining arrays or objects, and spreading an array out into a function’s arguments. You can find more info on this [link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) – Naren Jan 10 '21 at 14:15
  • `const`s are not reassignable but you can change the `property values` for reference types. `const person = { name: 'A '}`, `person.name = 'B' -> is valid`, `person = {name: 'B'} is invalid`. Read more about const [here](https://stackoverflow.com/questions/23436437/why-can-i-change-value-of-a-constant-in-javascript) – Naren Jan 10 '21 at 14:20
1

this problem is so usual. React is not a simple appender to DOM. Use defaultChecked instead of checked.

Tomáš Wróbel
  • 658
  • 3
  • 12
1

You're using the same array(var temp = check). So the component will not rerender.

const handleChange = (event) => {
  const { id, checked } = event.target;
  const index = name.indexOf(id);
  setCheck(prevChecks => {
      const newChecks = [...prevChecks];
      newChecks[index] = checked;
      return newChecks;
  });
};
Ramesh Reddy
  • 10,159
  • 3
  • 17
  • 32
1

I believe you have used an extra name array state in your code. I see no use case of this at all.

You can try this code and add ids into your object which contains status checked of checkboxes :) This is more performant code and uses less memory.

Here is the Full Code Demo:

const {useState, useEffect} = React;

function App() {
  const [check, setCheck] = useState([
    { id: 1, checked: true },
    { id: 2, checked: false }
  ]);

  const handleChange = (id) => {
    const updatedItems = check.map((item) => {
      if (item.id === id) {
        item["checked"] = !item["checked"];
        return item;
      }

      return item;
    });

    setCheck(updatedItems);
  };

  return (
    <div>
      {check.map((item, index) => {
        return (
          <div>
            <p>{item.id}</p>
            <input
              type="checkbox"
              checked={item["checked"]}
              onChange={() => handleChange(item.id)}
              id={item.id}
              key={item.id}
            />
          </div>
        );
      })}
    </div>
  );
}

ReactDOM.render(<App/>, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
Imran Rafiq Rather
  • 7,677
  • 1
  • 16
  • 35