Home > OS >  React.js and Firebase querySnapshot.forEach replacing array with identical objects
React.js and Firebase querySnapshot.forEach replacing array with identical objects

Time:02-08

I've been facing this issue for a couple of days where I have an array named tempTaskArray, which stores objects filled with data taken from my firestore database.

These objects contain the correct data on each iteration of the .forEach method but when put into my state variable, "tasks" (an array), from array tempTaskArray, all objects contain the data of the last created object.

This issue is not run into when I have an array of strings.

See code below:

      const getTasks = () => {
    db.collection("users").doc(uid).collection("tasks")
    .orderBy("epochdate", "asc")
    .get()
    .then((querySnapshot) => {
        querySnapshot.forEach((doc) => {

          // populates array with strings
          // tempTaskArray.push(doc.data().taskname)

          // tempTaskObject is an empty object
          tempTaskObject.taskname= doc.data().taskname
          tempTaskObject.duedate= doc.data().duedate

          // gets epoch date value and stores it
          var epochDate = doc.data().epochdate;

          // gets current time
          const day = new Date();
          let currentTime = day.getTime();

          // finds time remaining in epoch 
          var timeRemaining = epochDate - currentTime;

          // finds how many days are left and rounds down
          var daysLeft = (timeRemaining / 86400000)
          daysLeft = Math.floor(daysLeft)

          tempTaskObject.duein = daysLeft

          tempTaskArray.push(tempTaskObject)

        });
        setTasks(tempTaskArray)

    })
    .catch((error) => {
        console.log("Error getting documents: ", error);
    });
  }
  getTasks();

The data taken populating state variable "task" is then rendered in component Task seen below:

    <div>
      {tasks.map((task) => (
      <Task
        key={task}
        task__title={task.taskname}
        due__date={task.duedate}
        days__away={task.duein}
      />
    ))}
    </div>

I would be extremely grateful for an explanation of why this is happening. Thanks in advance

CodePudding user response:

Based on the provided code I believe it's an error of adding the reference of the tempTaskObject to the tempTaskArray and changing the same referenced object on each iteration.

To avoid this you can reassign a new Object to tempTaskObject on every iteration, like

.then((querySnapshot) => {
    querySnapshot.forEach((doc) => {

      // tempTaskObject is (now really) an empty object
      tempTaskObject = {};
      tempTaskObject.taskname= doc.data().taskname;

Further Explanation

I believe it worked before with String types, because these are primitive datatypes which will just be copied into the tempTaskArray.

The current tempTaskObject though has multiple properties (duein, taskname, duedate) and is therefore a complex object. When pushing objects to an javascript array, it adds the reference to the object to the array, NOT a copy. In your example you always keep the reference to the tempTaskObject and that's why it always changes the properties of the exact same object.

Examples

// Array with Primitives
const animalNames = ['Tiger', 'Spider'];
console.log('animalNames', animalNames);
let scaryName = animalNames[1];
scaryName = 'Goldfish';
console.log('still scary animalNames', JSON.stringify(animalNames)); // nothing changed, because we're working with a copy

// Array with Objects
const animals = [{
  name: 'Tiger',
  teeth: 30,
  legs: 4
}, {
  name: 'Spider',
  teeth: 0,
  legs: 8
}];
console.log('animals', animals);
let scaryAnimal = animals[1]; // storing a reference to the spider object
scaryAnimal.name = 'Goldfish';
scaryAnimal.legs = 0;
console.log('less scary animals', animals); // spider got replaced by a goldfish

// Now we'll want to add another animal the WRONG WAY
// FIX: Uncomment line below to properly add a bunny
// scaryAnimal = {};
scaryAnimal.name = 'Bunny';
scaryAnimal.legs = 4;
scaryAnimal.teeth = 2;
animals.push(scaryAnimal);
console.log('duplicated animal', JSON.stringify(animals));

Edit: Fixed typo

  •  Tags:  
  • Related