Home > database >  Unwanted modification in State variable (Hook), due to manipulation of local variable
Unwanted modification in State variable (Hook), due to manipulation of local variable

Time:03-27

The function "manipulateData" given below modifies a local variable "tempArray" but the changes are reflecting in the global variable "data" as well.

import React, { useState, useEffect } from "react";

export const Test = () => {
  const [data, setData] = useState([]);
  const file = [{ id: 1, description: "Test Data" }];

  useEffect(() => setData(file), []);

  const manipulateData = (data) => {
    let tempArray = [...data];
    tempArray.map((item) => delete item.id);
  };

  return (
    <>
      <h1>Testing Data</h1>
      {manipulateData(data)}
      {console.log(data)}
    </>
  );
};

Something is wrong with the code or my concept?

My current understanding is that:
consider the following declaration of a State Variable: const [mango, setMango] = useState(initialState); I understand that any modification to 'mango' can be done only via 'setMango'

I want to make modification to the local variable "tempArray", and the changes shall not reflect in the variable "data"

CodePudding user response:

This happens because you are creating a new array, but the objects in that array are not deeply copied. Instead, they represent just a reference to the very same objects as in data.

Because both references are pointing at the same object, if you delete an object property from the tempArray objects, you are actually deleting it from the data objects.

If you want to solve this, you have to destroy the reference by making a deep copy of the objects from the data array.

Here is an example how to do it:

export const Test = () => {
  const [data, setData] = useState([{ id: 1, description: "Test Data" }]);

  const manipulateData = (data) => {
    let tempArray = data.map((item) => {item.description}); //this will create an array with new object, and destroy the reference to the objects of data.
  };

  return (
    <>
      <h1>Testing Data</h1>
      {manipulateData(data)}
      {console.log(data)}
    </>
  );
};

Also, instead of deleting a property, better pick the one that you need.

CodePudding user response:

The following code:

let tempArray = [...data];

only shallow copies your data array, meaning that any of the objects inside of tempArray refer to the same objects in memory that are within the data array. This means that when you loop over your objects with .map(), each item refers to an object from data as well, which results in the objects in data changing when you use delete item.id.

Currently, you are using .map() just to loop over your tempArray, this isn't the purpose of .map(). The .map() method returns a new array, and the callback function you pass it should return a new value that you want to map the current value to. This means you can use .map() to create tempArray, by making the callback function return a new object that excludes the id property:

const manipulateData = (data) => {
  const tempArray = data.map(({id, ...rest}) => rest);
  // ... do what you need with `tempArray` ...
};

Above, {id, ...rest} is destructuring assignment syntax, which extracts the id property from the current element, and stores all other properties/values from the current object in rest. This allows you to create a new object that excludes the id property.

As a side note, you shouldn't be calling methods such as console.log() and manipulateData() inside of JSX if they don't return anything meaningful that will be rendered to the screen, instead, you can put these in a useEffect() hook.

CodePudding user response:

const [data, setData] = useState([{ id: 1, description: "Test Data" }]);

try this

CodePudding user response:

Your way is right in case you are not using a multi-dimensional array, but here you are cloning a multi-dimensional array, and by using the = operator, it’ll assign objects/arrays by reference instead of by value! That means whenever you modify any of the two objects it's going to affect the value in both.

A good way to solve this is by creating a deep clone by doing something like this

    const tempArray = JSON.parse(JSON.stringify([...data]))
    tempArray.map((item) => delete item.id)
  • Related