1

I'm using an object in two different states, in on of the states I just set the object in the state, and the other state I change one of the values in the object before setting state, but when I make the change both of the states change.

  const fetchCategories = () => {
    setAllCategory(categoryList1["movies"]);

    categoryList1["movies"].forEach((i) => {
      setMovies((prev) => {
      i["favmovies"] = [];
      return [...prev, i];
     });
   });
 };

both states return an empty favmovies array

[
    {
        "id": "1",
        "name": "development",
        "image": "img.png",
        "favmovies": []
    },
    {
        "id": "2",
        "name": "socialmedia",
        "image": "img2.png",
        "favmovies": []
    },
    {
        "id": "3",
        "name": "writing",
        "image": "img2.png",
        "favmovies": []
    }
]
  • 1
    See [React: Updating state when state is an array of objects](https://stackoverflow.com/questions/37662708/react-updating-state-when-state-is-an-array-of-objects?rq=1) and [How to update nested state properties in React](https://stackoverflow.com/questions/43040721/how-to-update-nested-state-properties-in-react) – Shivam Jha Oct 06 '21 at 17:42
  • ^ agreed, even outside react you need to consider the risk of updating objects by value/reference accordingly. The safest way would be: create a new variable which contains the original object you want to modify, modify this "copy", return the "copy" as your update – AGE Oct 06 '21 at 17:46
  • I tried creating a new variable then modified the object and return it and still the the other state changed and I even tried to push the objects to an array and still the other object was modified @ShivamJha – Nasereddin Kailani Oct 06 '21 at 18:02
  • const ll = []; const catlist = categoryList1["movies"]; catlist.forEach((i) => { i["favmovies"] = []; ll.push(i); }); console.log(ll); @AGE – Nasereddin Kailani Oct 06 '21 at 18:03
  • look at `Object.assign` for example `newObject = Object.assign({} , myObject)` – AGE Oct 06 '21 at 19:44

1 Answers1

0

Issue

You are still mutating an object reference:

const fetchCategories = () => {
  setAllCategory(categoryList1["movies"]);

  categoryList1["movies"].forEach((i) => {
    setMovies((prev) => {
      i["favmovies"] = []; // <-- mutation is here
      return [...prev, i];
    });
  });
};

i["favmovies"] = []; mutates the i object that is still a reference in the categoryList1.movies array.

Solution

From what I can tell, you want to store categoryList1.movies array into the allCategory state, and then a copy of categoryList1.movies array with the favmovies array emptied/reset to an empty array.

Instead of for-each iterating over the categoryList1.movies array and enqueueing multiple state updates, just map categoryList1.movies array to a new array reference for the movies state.

const fetchCategories = () => {
  setAllCategory(categoryList1["movies"]);
  setMovies(movies => movies.concat(     // <-- add to existing state
    categoryList1.movies.map(movie => ({ // <-- map to new array
      ...movie,                          // <-- shallow copy movie object
      favmovies: [],                     // <-- update property
    }))
  ));
};
Drew Reese
  • 165,259
  • 14
  • 153
  • 181