0

Given the following code:

I am expecting staticData not to change when gridData does.

import { useState } from "react";
import "./styles.css";

const CheckData = (props) => {
  return (
    <>
      <h1>Data From {props.ds}</h1>
      {props.items.map((row) => (
        <div key={row.recordid}>{row.companyname}</div>
      ))}
    </>
  );
};

export default function App() {
  const [gridData, setGridData] = useState([
    {recordid: 1,companyname: "Devshare"},
    {recordid: 2,companyname: "Shufflebeat"},
    {recordid: 3,companyname: "Mita"}
  ]);

  const staticData = [...gridData];

  const changeValue = () => {
    let nd = gridData;
    nd[2]["companyname"] = "Superman";
    setGridData([...nd]);
  };

  return (
    <div className="App">
      <CheckData ds="gridData" items={gridData} />
      <CheckData ds="staticData" items={staticData} />
      <button style={{ marginTop: "50px" }} onClick={changeValue}>
        Change a value in gridData
      </button>
    </div>
  );
}

Why does value in staticData change when gridData does? I thought I made a copy of the object - not create an instance.

Code SandBox Test Code Here

5
  • 3
    Spread only shallow copies. If you have nested, complex data you'll need to copy your state deeply Commented Jan 5, 2022 at 20:28
  • If you want to do a deep clone, i have had a lot of success with lodash's _.cloneDeep() lodash.com/docs/4.17.15#cloneDeep Commented Jan 5, 2022 at 20:29
  • Even with a deep clone... On every render you construct staticData from what's in gridData. Why would it ever be different than what's in gridData? Commented Jan 5, 2022 at 20:32
  • Fair enough but this is not a complex copy (or is it). Why didn't [...gridData] make an effective copy rather than an instance? Commented Jan 5, 2022 at 20:33
  • @David staticData is suppose to be a "history" table allowing users to undo things. Commented Jan 5, 2022 at 20:34

1 Answer 1

1

Based on a comment on the question:

staticData is suppose to be a "history" table allowing users to undo things.

Then you're building it in the wrong place. When you do this in the component:

const staticData = [...gridData];

Then on every render you re-build staticData based on the current values in gridData. So when the gridData state is updated and the component re-renders, you build a new staticData with the new values.

If staticData is supposed to be unchanging hard-coded data, define it outside the component:

const staticData = [
  {recordid: 1,companyname: "Devshare"},
  {recordid: 2,companyname: "Shufflebeat"},
  {recordid: 3,companyname: "Mita"}
];

And then within the component use it as the initial state value for gridData:

export default function App() {
  const [gridData, setGridData] = useState(staticData);

  //...
};

That way staticData is only defined once in the module. gridData can be updated in state as many times as you like but that won't affect staticData.

Sign up to request clarification or add additional context in comments.

5 Comments

Hard-coded data was used for simplicity - the data will be coming from an API call.
@Elcid_91: Alternatively you might track it in its own state value then. Either way the main point is that you can't track two different sets of data in the same state, which is what the code in the question is currently trying to do.
David - so you are saying that when I clicked that button and the re-render occurs, that let staticState=[...gridData] would be executed again?
@Elcid_91: Correct. The component itself (in this case App) is a function and that function is executed on every render.
Makes total sense now. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.