【问题标题】:React component doesn't update DOMReact 组件不更新 DOM
【发布时间】:2021-03-21 20:41:43
【问题描述】:

代码沙盒:https://codesandbox.io/s/trusting-chandrasekhar-3jpw4

我正在开发战舰游戏应用程序。在这个游戏中,用户可以点击对手的网格并选择要攻击的单元格。如果一个单元格被攻击并且它包含一艘敌舰,那么它应该有一个应用到它的类,因此会变成红色。

我遇到了一个问题,即所有功能都在工作,但在进行移动时组件没有更新。如果我进入我的组件代码做一个小改动然后保存它,我可以看到选定的单元格变成红色(如果它包含一艘敌舰)。

GameboardSetup 组件生成初始网格:

const createUiGrid = () => {
        const cells = [];
        for (let i = 0; i < 100; i++) {
          cells.push(i);
        }
        let counter = -1;
        const result = cells.map((cell) => {
          counter++;
          return (
            <div
              className="cell"
              id={counter}
              onClick={onClickHandler}
              onMouseOut={onMouseOutHandler}
              onMouseOver={onMouseOverHandler}
            />
          );
        });
        return result;
    };

    const generateAiGrid = () => {
        let aiPlacedShips = 0;
        let currentShipLength = null;
        let currentShipDirection = null;

        const generateShipDirection = () => {
            let randomNumber = Math.floor(Math.random() * 2);
            if (randomNumber === 0) {
                return 'horizontal'
            }
            return 'vertical'
        }

        while (aiPlacedShips <= 4) {
            let unavailableCells = [];
            currentShipDirection = generateShipDirection();

            if (aiPlacedShips === 0) {
                currentShipLength = 5;
            } else {
                currentShipLength = ships[aiPlacedShips].length;
                for (let i = 0; i < aiGameboard.shipYard.length; i++) {
                    aiGameboard.shipYard[i].position.forEach((val) => {
                        unavailableCells.push(val);
                    })
                };
            };

            const generateRandom = (min, max) => {
                const num = Math.floor(Math.random() * (max - min + 1)) + min;
                return (unavailableCells.includes(num)) ? generateRandom(min, max) : num;
            }
            
            let currentShipStartCell = generateRandom(0, 99);
            let currentShipEndCell = null;
            
            if (currentShipDirection === 'horizontal') {
                currentShipEndCell = currentShipStartCell + currentShipLength - 1;
            } else {
                currentShipEndCell = currentShipStartCell + ((currentShipLength - 1) * 10);
            };
    
            if ((aiGameboard.checkValidCoordinates(currentShipDirection, currentShipStartCell, currentShipEndCell)) && (!aiGameboard.checkIfShipPresent(currentShipDirection, currentShipStartCell, currentShipEndCell))) {
                aiGameboard.placeShip(aiPlacedShips, currentShipDirection, currentShipStartCell, currentShipEndCell);
                aiPlacedShips++;
            };
        };
    };

然后将它们传递给 App 组件并通过以下 useEffect 函数存储在状态中:

useEffect(() => {
        if (placedShips >= 5){
            props.handleNextStepChange();
            props.setPlayerSetupGameboard(playerGameboard);
            props.setAiSetupGameboard(aiGameboard);
        }
    }, [placedShips]);

这些网格然后通过 props 传递给 Game 组件:

    const showNextComponent = () => {
        if (phase === 1) {
            return (
                <GameboardSetup 
                    setPlayerSetupGameboard={setPlayerSetupGameboard}
                    setAiSetupGameboard={setAiSetupGameboard}
                    handleNextStepChange={handleNextStepChange}
                />
            );
        } else if (phase === 2) {
            return (
                <Game 
                    playerSetupGameboard={playerSetupGameboard}
                    aiSetupGameboard={aiSetupGameboard}
                />
            );
        } else {
            return (
                <Intro
                    setPlayerName={setPlayerName}
                    handleNextStepChange={handleNextStepChange}
                />
            );
        };
    };

然后将网格存储到 Game 组件中的状态中:

    useEffect(() => {
        setPlayerGameboard(props.playerSetupGameboard);
        setAiGameboard(props.aiSetupGameboard);
    }, [props]);

然后在 Game 组件中生成网格:

const createPlayerGrid = (playerGameboard) => {

        if (!!playerGameboard) {

            let ships = [];
            let hitShips = [];

            for (let i = 0; i < playerGameboard.shipYard.length; i++) {
                playerGameboard.shipYard[i].position.forEach((cell) => {
                    ships.push(cell);
                });
            };

            for (let i = 0; i < playerGameboard.shipYard.length; i++) {
                playerGameboard.shipYard[i].hits.forEach((cell) => {
                    hitShips.push(cell);
                });
            };

            const cells = [];
            for (let i = 0; i < 100; i++) {
                cells.push(i);
            }
            let counter = -1;
            const result = cells.map((cell) => {
                let shipStatus = '';
                counter++;
                if (ships.includes(counter)) {
                    shipStatus = 'ship';
                }
                if (hitShips.includes(counter)) {
                    shipStatus = 'hit-ship';
                }
                return (
                    <div
                        className={`player-cell ${shipStatus}`}
                        id={counter}
                    />
                );
            });
            return result;  
        }
    };

    const createAiGrid = (aiGameboard) => {

        if (!!aiGameboard) {

            let ships = [];
            let hitShips = [];

            for (let i = 0; i < aiGameboard.shipYard.length; i++) {
                aiGameboard.shipYard[i].position.forEach((cell) => {
                    ships.push(cell);
                })
            }
            for (let i = 0; i < aiGameboard.shipYard.length; i++) {
                aiGameboard.shipYard[i].hits.forEach((cell) => {
                    hitShips.push(cell);
                });
            };

            const cells = [];
            for (let i = 0; i < 100; i++) {
                cells.push(i);
            }
            let counter = -1;
            const result = cells.map((cell) => {
                let shipStatus = '';
                counter++;
                if (ships.includes(counter)) {
                    shipStatus = 'ship';
                }
                if (hitShips.includes(counter)) {
                    shipStatus = 'hit-ship';
                }
                return (
                    <div
                        className={`ai-cell ${shipStatus}`}
                        id={counter}
                        onClick={onClickHandler}
                    />
                );
            });
            return result;  
        }
    };

这些函数的结果随后会在返回函数中呈现:

    return (
        <div className="main-container">
            <div className="player-container">
                <div className="player-grid">
                    <Table grid={createPlayerGrid(playerGameboard)} />
                </div>
            </div>
            <div className="ai-container">
                <div className="ai-grid">
                    <Table grid={createAiGrid(aiGameboard)} />
                </div>
            </div>
        </div>
    );

正如我上面提到的,如果我对 Game 组件进行了修改并在进行有效的命中移动后将其保存,则命中船类将附加到该单元格并变为红色。

我不确定为什么会发生这种情况,但我对 React 比较陌生,非常感谢任何建议。

谢谢!

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    首先,我不会两次使用相同的状态并让它们与 useEffect 函数保持同步。 我推荐如下使用 React 上下文 创建 Context.Provider 并传递值。 (甚至可能是 setValue 函数) 在每个组件内部,不要通过道具传递那些共享状态。而是使用 React.useContext() 函数 签出:https://reactjs.org/docs/context.html

    【讨论】:

      【解决方案2】:

      onClickHandler 只触发了一次,现在正在使用以下功能:

          const onClickHandler = (e) => {
              if (turn === true) {
                  console.log(aiGameboard)
                  humanPlayer.attack(aiGameboard, e.target.id);
              };
              console.log(aiGameboard)
              humanPlayer.attack(aiGameboard, e.target.id);   // TEMPORARY
              toggleTurn();
          };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-02-06
        • 2021-07-20
        • 1970-01-01
        • 1970-01-01
        • 2021-11-15
        • 2016-06-30
        • 1970-01-01
        相关资源
        最近更新 更多