简体   繁体   中英

Unexpected mutation of array in React

I am just learning to program and am writing one of my first applications in React. I am having trouble with an unexpected mutation that I cannot find the roots of. The snippet is part of a functional component and is as follows:

const players = props.gameList[gameIndex].players.map((item, index) => {
    const readyPlayer = [];
    props.gameList[gameIndex].players.forEach(item => {
      readyPlayer.push({
        id: item.id,
        name: item.name,
        ready: item.ready
      })
    })
    console.log(readyPlayer);
    readyPlayer[index].test = "test";
    console.log(readyPlayer);
    return (
      <li key={item.id}>
        {/* not relevant to the question */}
      </li>
    )
  })

Now the problem is that readyPlayer seems to be mutated before it is supposed to. Both console.log's read the same exact thing. That is the array with the object inside having the test key as "test". forEach does not mutate the original array, and all the key values, that is id, name and ready, are primitives being either boolean or string. I am also not implementing any asynchronous actions here, so why do I get such an output? Any help would be greatly appreciated.

Below is the entire component for reference in its original composition ( here also the test key is replaced with the actual key I was needing, but the problem persists either way.

import React from 'react';

import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
// import styles from './Lobby.module.css';

const Lobby = ( props ) => {

  const gameIndex = props.gameList.findIndex(item => item.id === props.current.id);
  const isHost = props.gameList[gameIndex].hostId === props.user.uid;

  const players = props.gameList[gameIndex].players.map((item, index) => {
    const isPlayer = item.id === props.user.uid;
    const withoutPlayer = [...props.gameList[gameIndex].players];
    withoutPlayer.splice(index, 1);
    const readyPlayer = [];
    props.gameList[gameIndex].players.forEach(item => {  
      readyPlayer.push({
        id: item.id,
        name: item.name,
        ready: item.ready
      })
    })
    const isReady = readyPlayer[index].ready;
    console.log(readyPlayer);
    console.log(!isReady);
    readyPlayer[index].ready = !isReady;
    console.log(readyPlayer);
    return (
      <li key={item.id}>
        {isHost && index !== 0 && <button onClick={() => props.updatePlayers(props.gameList[gameIndex].id, withoutPlayer)}>Kick Player</button>}
        <p>{item.name}</p>
        {isPlayer && <button onClick={() =>props.updatePlayers(props.gameList[gameIndex].id, readyPlayer)}>Ready</button>}
      </li>
    )
  })

  let showStart = props.gameList[gameIndex].players.length >= 2;
  props.gameList[gameIndex].players.forEach(item => {
    if (item.ready === false) {
      showStart = false;
    }
  })

  console.log(showStart);

  return (
    <main>
      <div>
        {showStart && <Link to="/gameboard" onClick={props.start}>Start Game</Link>}
        <Link to="/main-menu">Go back to Main Menu</Link>
      </div>
      <div>
        <h3>Players: {props.gameList[gameIndex].players.length}/4</h3>
         {players}
      </div>
    </main>
  );
}

Lobby.propTypes = {
  start: PropTypes.func.isRequired,
  current: PropTypes.object.isRequired,
  gameList: PropTypes.array.isRequired,
  updatePlayers: PropTypes.func.isRequired,
  user: PropTypes.object.isRequired

}

export default Lobby;

Note: I did manage to make the component actually do what it is supposed, but the aforementioned unexpected mutation persists and is still a mystery to me.

I have created a basic working example using the code snippet you provided. Both console.log statements return a different value here. The first one returns readyPlayer.test as undefined , the second one as "test" . Are you certain that the issue happens within your code snippet? Or am I missing something?

(Note: This answer should be a comment, but I am unable to create a code snippet in comments.)

 const players = [ { id: 0, name: "John", ready: false, }, { id: 1, name: "Jack", ready: false, }, { id: 2, name: "Eric", ready: false } ]; players.map((player, index) => { const readyPlayer = []; players.forEach((item)=> { readyPlayer.push({ id: item.id, name: item.name, ready: item.ready }); }); // console.log(`${index}:${readyPlayer[index].test}`); readyPlayer[index].test = "test"; // console.log(`${index}:${readyPlayer[index].test}`); }); console.log(players)

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