Я реализую функцию завершения раунда для настольной игры. Каждое состояние игроков представлено объектом, который в свою очередь сохраняется в массиве playerStates:
const [playerStates, setPlayerStates] = useState(getInitialPlayerStates);
const [playerIndex, setPlayerIndex] = useState(0);
const playerState = playerStates[playerIndex];
function setPlayerState(playerState) {
let tPlayerStates = [...playerStates];
tPlayerStates.splice(playerIndex, 1, playerState);
setPlayerStates(tPlayerStates);
}
Функция конца раунда проверяет, все ли игроки завершили свои действия, и, если да, сбрасывает глобальное состояние
/** END OF ROUND **/
function handleEndRound() {
let nextPlayerIndex = playerIndex + 1 < GLOBAL_VARS.numOfPlayers ? playerIndex + 1 : 0;
let haveAllFinished = true;
while (playerIndex !== nextPlayerIndex) {
if (!playerStates[nextPlayerIndex].finishedRound) {
haveAllFinished = false;
}
nextPlayerIndex = nextPlayerIndex + 1 < GLOBAL_VARS.numOfPlayers ? nextPlayerIndex + 1 : 0;
}
if (haveAllFinished) {
...
/* reset player states */
let tPlayerStates = [];
for (let i = 0; i < GLOBAL_VARS.numOfPlayers; i++) {
let tPlayerState = {...playerStates[i]};
console.log("RESETTING PLAYER STATE:");
console.log(tPlayerState);
tPlayerState.availableAdventurers = GLOBAL_VARS.adventurers;
/* remove active card */
if (tPlayerState.activeCard !== false) {
tPlayerState.discardDeck.push(tPlayerState.activeCard);
tPlayerState.activeCard = false;
}
/* move cards from hand to discard */
for (let card of tPlayerState.hand) {
tPlayerState = addCardToDiscardDeck(card, tPlayerState);
tPlayerState.hand = [];
}
console.log("tPlayerState before:");
console.log(tPlayerState);
/* draw a new hand */
for (let i = 0; i < GLOBAL_VARS.handSize; i++) {
if (tPlayerState.drawDeck.length === 0) {
console.log("tPlayerState after:");
console.log(tPlayerState);
tPlayerState = addDiscardToDrawDeck(tPlayerState);
}
if (tPlayerState.drawDeck.length > 0) {
tPlayerState = addCardToHand(tPlayerState.drawDeck[0], playerState);
tPlayerState.drawDeck.splice(0, 1);
}
}
...
Проблема в том, что сохраняется неправильное состояние игрока, о чем свидетельствуют выводы консоли:
tPlayerState before: App.js:315
Object { finishedRound: true, ... color: "#FFD41A" }
tPlayerState after: App.js:320
Object { finishedRound: false, ... color: "#2A8CFF" }
Цвет идентифицирует игроков, и по какой-то причине меняется состояние первого игрока от состояния второго игрока.
Многое происходит с глубоко вложенными объектами и массивами, и это может быть причиной - однако я не понимаю, почему именно эти два вывода должны различаться. Что является источником изменений? Как я могу предотвратить это?
Полный код размещен на https://github.com/faire2/loreHunters/.
Дополнительная информация: Проблема относится к JS, а не к Реакции. Проблема была связана с передачей мелкой копии глубокого объекта функции. Я до сих пор не понимаю, что именно происходило: в конце концов два странно слитых объекта помещались в массив, хотя я выдвигал только один объект.