简体   繁体   中英

Array in React being mutated

I've read several entries on keeping arrays from being mutated in React, but I can't figure out why my original array is being mutated. In the componentDidMount, I'm going to the database and retrieving win-loss records for each week and saving the records to state. (Each week a team plays three games.)

async componentDidMount() {
    document.body.style.background = '#9bcaf1';
    await this.getInitialStats();
    this.processStats();
  }

  async getInitialStats(): Promise<void> {
    const allRecords: TeamWeek[] = await getAllResults();
    this.setState({
      allRecords,
    });
  }

Then I call a second function that takes each team's record for the week and combines them into one record. So if a team has lost all three games in each of three weeks, that should combine to one record that shows the team lost nine games. I save that as a separate state variable. However the original state array is being mutated as well, even though I thought I was cloning the array. I can do a push into the cloned array, and it works correctly, but something with the function is screwing things up.

processStats(): void {
    const allRecordsClone = [...this.state.allRecords];
    const combinedRecords: TeamWeek[] = calculateOverallStats(allRecordsClone);
    this.setState({
      combinedRecords,
    });
  }
export const calculateOverallStats = (allRecords: TeamWeek[]): TeamWeek[] => {
  const allRecordsClone = [...allRecords];
  const combinedRecs: TeamWeek[] = [];
  const teamNamesCollected: string[] = [];

  // Combine wins, losses, ties, points
  allRecordsClone.forEach((rec) => {
    const { team_name, wins, losses, ties, total_points } = rec;
    if (!teamNamesCollected.includes(team_name)) {
      combinedRecs.push(rec);
      teamNamesCollected.push(team_name);
    } else {
      const teamIndex = combinedRecs.findIndex((combRec) => combRec.team_name === team_name);
      combinedRecs[teamIndex].wins += wins;
      combinedRecs[teamIndex].losses += losses;
      combinedRecs[teamIndex].ties += ties;
      combinedRecs[teamIndex].total_points += total_points;
    }
  });
  return allRecordsClone;
};

Any thoughts? I cannot figure this out.

Copying an array via spread still creates references to any objects included in the array.

 const array1 = [1, {a: 2}, [3,4]]; const array2 = [...array1]; array2[0] = "unchanged in array1"; array2[1].a = "changed in both"; array2[2][0] = "arrays are Objects"; console.log('array1: ', array1); // array1: [1, {"a": "changed in both"}, ["arrays are Objects", 4]] console.log('array2: ', array2); // array2: ["unchanged in array1", {"a": "changed in both"}, ["arrays are Objects", 4]]

Given that, you'll need to use Object.assign() or spread each object or array before pushing into the combinedArray.

The React docs cover this issue here: Immutability Helpers

@pilchard's answer is correct. First you need to create copy of each property or element of array, and then push it to parent combined array. You need can use either of Object.assign() or spread operator to do this.

Object spread vs. Object.assign

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM