Home > OS >  React useState not updating mapped content
React useState not updating mapped content

Time:08-29

I feel like im missing something that is staring me right in the face. I am trying to have content stored in an array of objects update when a checkbox is on or off. The console log is showing the object data is updating correctly so I assume my fault resides in not understanding useState fully?

const [statistics, setStatistics] = useState([
    {
        id: 1,
        content: <div>Content1</div>,
        state: true,
    },
    {
        id: 2,
        content: <div>Content2</div>,
        state: true,
    },
]);

In the component:

{statistics.map((item) => (item.state ? item.content : <></>))}

<input
type="checkbox"
    onChange={(e) => {
        let newArr = statistics;
        e.target.checked
            ? (newArr[0].state = true)
            : (newArr[0].state = false);
        setStatistics(newArr);
        console.log(statistics);
    }}
/>

CodePudding user response:

You are trying to change the state directly, instead you need to work with a copy of the state and make all changes to it.

Just replace in your code this string:

let newArr = statistics; // as link to base array

to

let newArr = [...statistics]; // as new copy of base array

and it will works. React skips all state changes if they are made directly.

CodePudding user response:

To create a new array as copy/clone of another array, in ES6, we can use the spread operator. You can not use = here, since it will only copy the reference to the original array and not create a new variable. Just read here for reference.

In your case, your newArray will refer to the old statistics and will not be detected as the new state. That is why no re-render takes place after you made changes to it.

So here, you can do this:

  return (
    <>
      {statistics.map((item) => (item.state ? item.content : <></>))}
      <input
        type="checkbox"
        onChange={(e) => {
          setStatistics((prevStats) => {
            const newStats = [...prevStats];
            e.target.checked
              ? (newStats[0].state = true)
              : (newStats[0].state = false);
            return newStats;
          });
        }}
      />
    </>
  );
  • Related