skip to Main Content

Let’s say I have a code scenario like this….

const obj = {
   dogs: ["terrier", "labrador", "poodle"],
   ages: [4,6,11],
   names: ["Fido", "Max", "Spot"]
};

const [data, setData] = useState(obj);

Then, I want to change one of the names in the array to Richard, for example. How can I do this efficiently?

What I’ve been doing is cloning the object with let clone = JSON.parse(JSON.stringify(obj)) then modifying the clone, then calling setData(clone). I feel like there has got to be a better way though where I don’t have to clone the object.

3

Answers


  1. As pilchard commented you need to do a copy to trigger a change, but you can do with the new deep clone:

    let clone = structuredClone(obj);
    
    Login or Signup to reply.
  2. If you don’t clone the object React doesn’t know that you have updated state since it is checked by reference equality. That being said the JSON approach isn’t great, see What is the most efficient way to deep clone an object in JavaScript? for full discussion.

    But a deep clone is actually unnecessary in this situation, a shallow copy of the containing object, and a clone of any mutated nested objects is sufficient. Here is an example updating the nested dogs array using spread syntax to clone the object and map() to update the necessary nested array.

    const obj = {
      dogs: ["terrier", "labrador", "poodle"],
      ages: [4, 6, 11],
      names: ["Fido", "Max", "Spot"],
    };
    
    const [data, setData] = useState(obj);
    
    const updateDogs = (oldValue, newValue) =>
      setData(prevData => ({
        ...prevData,
        dogs: prevData.dogs.map(dog => (dog === oldValue ? newValue : dog)),
      }));
    
    Login or Signup to reply.
  3. My advice would be to split it into 3 state values:

    const [dogs, setDogs] = useState(["terrier", "labrador", "poodle"]);
    const [ages, setAges] = useState([4,6,11]);
    const [names, setNames] = useState(["Fido", "Max", "Spot"]);
    

    To change a name, you can then clone the names collection (instead of the entire object) and update that:

    const newNames = [...names];
    newNames[someIndex] = theNewName;
    setNames(newNames);
    

    To me this makes it much clearer that only a certain part of the state is being updated, and it eliminates the risk of inadvertent changes to other parts of the state.

    Also it is more efficient, although for such a small dataset the difference will not be noticeable.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search