Неожиданное изменение объекта - PullRequest
0 голосов
/ 16 марта 2020

Я реализую функцию завершения раунда для настольной игры. Каждое состояние игроков представлено объектом, который в свою очередь сохраняется в массиве 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, а не к Реакции. Проблема была связана с передачей мелкой копии глубокого объекта функции. Я до сих пор не понимаю, что именно происходило: в конце концов два странно слитых объекта помещались в массив, хотя я выдвигал только один объект.

1 Ответ

0 голосов
/ 17 марта 2020

Проблема заключалась в передаче мелкой копии глубоко вложенного объекта в функцию и обратно. Проблема была решена путем передачи Loda sh глубокого клона этого объекта:

...
const result = addCardToHand(tPlayerState.drawDeck[0], cloneDeep(tPlayerState));
...

Я все еще хотел бы понять, что происходит, и почему два объекта, оба рассматриваются по отдельности в al oop, были объединены в один.

РЕДАКТИРОВАТЬ: так что кажется, что console.log не всегда показывает надлежащее состояние объекта. Я использовал «отладчик», чтобы приостановить выполнение и проверить реальное состояние соответствующих объектов, что устранило путаницу. Таким образом, сама проблема была вызвана мелкой копией, которая была исправлена ​​с помощью cloneDeep от Loda sh. Правильное состояние можно проверить с помощью отладчика;.

...