2

In the function formatHours() below, I am trying to assign newHours to selectedLocation.data.hours (an object)

I am using the spread operator to clone the object, so that when the function finishes selectedLocation.data.hours remains the same, but it doesn't. After this function runs, selectedLocationd.data.hours is now equal to newHours.

formatHours():

const formatHours = () => {
    // ERROR: trying to clone selectedLocation.data.hours, but not working
    const newHours = { ...selectedLocation.data.hours };

    // loop through all hours and convert them to javascript date with .toDate()
    for (const hour in newHours) {
      newHours[hour][0] = newHours[hour][0].toDate();
      newHours[hour][1] = newHours[hour][1].toDate();
    }

    // set hours state with updated hours
    setHours(newHours);
  };  

Here's what selectedLocation.data.hours looks like BEFORE passing it through formatHours():

(object of arrays of Firebase Firestore timestamps)

enter image description here

Here's what selectedLocation.data.hours looks like AFTER passing it through formatHours():

(object of arrays of Javascript Date objects)

enter image description here

NOTE: selectedLocation.data.hours should stay the same before and after the function, but doesn't. I must be missing something.

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
devon66h
  • 459
  • 4
  • 17
  • 1
    Does this answer your question? [How do I correctly clone a JavaScript object?](https://stackoverflow.com/questions/728360/how-do-i-correctly-clone-a-javascript-object) – romellem Feb 24 '21 at 14:55

2 Answers2

1

Instead of changing the newHours[hour] array (which mutates the object currently in state/props), create an entirely new array at that location, with the properties you need:

// Shallow clone newHours
const newHours = { ...selectedLocation.data.hours };
// Reassign each property; it'll affect the clone, not the original
for (const [hour, arr] of Object.entries(newHours)) {
  newHours[hour] = [
    arr[0].toDate(),
    arr[1].toDate(),
    arr[2]
  ];
}

Another method, with Object.fromEntries:

const newHours = Object.fromEntries(
    Object.entries(selectedLocation.data.hours).map(([hour, arr]) => (
        [ // return an entry array
            hour, // key in new object
            [ // value in new object
                arr[0].toDate(),
                arr[1].toDate(),
                arr[2]
            ]
        ]
    ))
);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

I'm not sure if it's the best way to do that, but you can do this

    const newHours = JSON.parse(JSON.stringify(selectedLocation.data.hours));

This will deep clone the object.

beartrap
  • 51
  • 2