首页 > 解决方案 > useEffect EventListener 问题 REACT HOOKS

问题描述

我试图用 REACT 制作一个简单的 Snake-Game。一切都很好,直到我需要在 keydown 触发时使用 useEffect 来移动“蛇”。当我尝试将 moveSnake() 放入 useEffect 时,它给了我一些错误。当我移动它并将其称为外部效果时,它会形成一个无限循环。我正在使用功能组件。App.js 搞砸了,因为我压力很大,因为它不起作用并尝试了每一个选项。希望你能得到一切。

https://github.com/Pijano97/snake-game代码在这里,谢谢。此外,如果有人无法访问,这里是代码。蛇组件只是用地图渲染蛇点。食物组件只是在地图上创建随机食物。

import { useEffect, useState } from "react";
import "./App.css";
import Snake from "./Snake";
import Food from "./Food";

function App() {
    const getRandomFoodDot = () => {
        let min = 1;
        let max = 98;

        let x = Math.floor((Math.random() * (max - min + 1) + min) / 2) * 2;
        let y = Math.floor((Math.random() * (max - min + 1) + min) / 2) * 2;

        return [x, y];
    };

    const [snakeDots, setSnakeDots] = useState([
        [0, 0],
        [2, 0],
    ]);
    const [foodDots, setFoodDots] = useState(getRandomFoodDot());
    const [direction, setDirection] = useState("");

    const moveSnake = () => {
        let dots = [...snakeDots];
        let head = dots[dots.length - 1];

        switch (direction) {
            case "UP":
                head = [head[0], head[1] - 2];
                break;
            case "DOWN":
                head = [head[0], head[1] + 2];
                break;
            case "LEFT":
                head = [head[0] - 2, head[1]];
                break;
            case "RIGHT":
                head = [head[0] + 2, head[1]];
                break;
            default:
                break;
        }
        // adding new head
        dots.push(head);
        // removing last dot
        dots.shift();
        setSnakeDots(dots);
    };

    moveSnake();

    useEffect(() => {
        const keyPressHandler = (e) => {
            switch (e.keyCode) {
                case 38:
                    setDirection("UP");
                    break;
                case 40:
                    setDirection("DOWN");
                    break;
                case 37:
                    setDirection("LEFT");
                    break;
                case 39:
                    setDirection("RIGHT");
                    break;
                default:
                    setDirection("");
                    break;
            }
        };
        document.addEventListener("keydown", keyPressHandler);
        return () => {
            document.removeEventListener("keydown", keyPressHandler);
        };
    }, []);

    console.log(direction);

    return (
        <div className="app">
            <div className="snake">
                <Snake snakeDots={snakeDots} />
                <Food foodDots={foodDots} />
            </div>
        </div>
    );
}

export default App;

标签: javascripthtmlreactjsuse-effectonkeydown

解决方案


您收到错误消息的原因是 React 将重新渲染的数量限制为经过验证的无限重新渲染是因为您在 App() 组件中调用 moveSnake() ,而 moveSnake() 调用 setSnakeDots() 来更新状态蛇点。当 snakeDots 的状态更新时,您的 App 组件会重新呈现,这会触发 moveSnake() 的调用,该调用会调用 setSnakeDots() 来更新您的 snakeDots 的状态,从而重新呈现您的 App 组件。你在这里陷入了一个无限循环。

可能会修复它的东西(尽管我对其进行了测试并且游戏没有继续进行一步)将在计时器中设置你的 moveSnake() 函数,比如

function timer(){
    setInterval(function() {
        moveSnake();
        timer()
    }, 1000);
}

timer()

推荐阅读