首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >useEffect EventListener problem REACT挂钩

useEffect EventListener problem REACT挂钩
EN

Stack Overflow用户
提问于 2020-12-13 09:27:54
回答 2查看 113关注 0票数 1

我试着用REACT做一个简单的Snake-Game。一切都很好,直到我需要使用useEffect来移动“蛇”时,按键射击。当我试图将moveSnake()放入useEffect中时,它给了我一些错误。当我移动它并调用它的外部效果时,它正在形成一个无限循环。我使用的是函数组件。App.js被搞得乱七八糟,因为我压力很大,因为它不能工作,我尝试了每一个选项。希望你能得到一切。

https://github.com/Pijano97/snake-game代码在这里,谢谢。另外,如果有人不能访问它,这里是代码。snake组件只是使用贴图呈现snakeDots。食物组件只是在地图上创建随机食物。

代码语言:javascript
复制
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;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-13 10:27:51

我不确定我是否正确,但也许你可以尝试一下:

代码语言:javascript
复制
import { useEffect, useState } from "react";
import "./App.css";
import Snake from "./Snake";
import Food from "./Food";

const getDirection = e => {
    switch (e.keyCode) {
        case 38:
            return 'UP';
        case 40:
            return 'DOWN';
        case 37:
            return 'LEFT';
        case 39:
            return 'RIGHT';
        default:
            return '';
    }
}

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({val: ''});

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

        switch (direction.val) {
            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);
    }, [direction]);

    useEffect(() => {
        const keyPressHandler = (e) => {
            setDirection({ val: getDirection(e) });
        };
        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;

我刚刚创建了一个用于从关键事件获取方向的getDirection函数,并使用来自moveSnake函数的逻辑添加了另一个useEffect。我不知道您项目的当前功能,但上面的代码可以工作,并且摇动可以移动。

票数 0
EN

Stack Overflow用户

发布于 2020-12-13 10:27:00

因为你在你的应用程序()组件中调用了moveSnake(),而moveSnake()调用了setSnakeDots()来更新snakeDots的状态,所以你会看到React限制了provent infinate重新渲染的数量。当snakeDots的状态更新时,您的应用程序组件会重新呈现,这会触发moveSnake()的调用,它会调用setSnakeDots()来更新snakeDots的状态,从而重新呈现您的应用程序组件。你被困在了一个inifinate循环中。

可以修复它的方法是在计时器中设置moveSnake()函数,如下所示

代码语言:javascript
复制
function timer(){
    setInterval(function() {
        moveSnake();
        timer()
    }, 1000);
}

timer()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65271583

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档