使用Effect EventListener问题REACT HOOKS
useEffect EventListener problem REACT HOOKS
我试图用 REACT 制作一个简单的贪吃蛇游戏。一切都很好,直到我需要使用 useEffect 在按键触发时移动“蛇”。
当我尝试将 moveSnake() 放入 useEffect 时,它给了我一些错误。当我移动它并将其称为外部效果时,它正在形成一个无限循环。我正在使用功能组件。 App.js 乱七八糟,因为我压力很大,因为它不起作用并尝试了每一个选项。希望你能得到一切。
https://github.com/Pijano97/snake-game 代码在这里,谢谢。
另外,如果有人无法访问它,这里是代码。
snake 组件只是用地图渲染 snakeDots。
食物组件只是在地图上创建随机食物。
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;
你得到这个错误的原因是 React 限制了重新渲染的数量以证明无限重新渲染是因为你在你的 App() 组件中调用了 moveSnake(),并且 moveSnake() 调用了 setSnakeDots( ) 更新 snakeDots 的状态。当 snakeDots 的状态更新时,您的 App 组件会重新呈现,这会触发 moveSnake() 的调用,这会调用 setSnakeDots() 来更新您的 snakeDots 的状态,从而重新呈现您的 App 组件。你在这里陷入了一个无限循环。
可能会解决它的方法(虽然我测试了它并且游戏不会继续超过一步)将在定时器中设置你的 moveSnake() 函数,比如
function timer(){
setInterval(function() {
moveSnake();
timer()
}, 1000);
}
timer()
我不确定我是否理解正确,但也许你可以试试这个:
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
函数来从关键事件中获取方向,并添加了一个 useEffect
具有来自 moveSnake
函数的逻辑
我不知道你的项目当前的功能,但是上面的代码可以运行,并且可以移动。
我试图用 REACT 制作一个简单的贪吃蛇游戏。一切都很好,直到我需要使用 useEffect 在按键触发时移动“蛇”。 当我尝试将 moveSnake() 放入 useEffect 时,它给了我一些错误。当我移动它并将其称为外部效果时,它正在形成一个无限循环。我正在使用功能组件。 App.js 乱七八糟,因为我压力很大,因为它不起作用并尝试了每一个选项。希望你能得到一切。
https://github.com/Pijano97/snake-game 代码在这里,谢谢。 另外,如果有人无法访问它,这里是代码。 snake 组件只是用地图渲染 snakeDots。 食物组件只是在地图上创建随机食物。
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;
你得到这个错误的原因是 React 限制了重新渲染的数量以证明无限重新渲染是因为你在你的 App() 组件中调用了 moveSnake(),并且 moveSnake() 调用了 setSnakeDots( ) 更新 snakeDots 的状态。当 snakeDots 的状态更新时,您的 App 组件会重新呈现,这会触发 moveSnake() 的调用,这会调用 setSnakeDots() 来更新您的 snakeDots 的状态,从而重新呈现您的 App 组件。你在这里陷入了一个无限循环。
可能会解决它的方法(虽然我测试了它并且游戏不会继续超过一步)将在定时器中设置你的 moveSnake() 函数,比如
function timer(){
setInterval(function() {
moveSnake();
timer()
}, 1000);
}
timer()
我不确定我是否理解正确,但也许你可以试试这个:
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
函数来从关键事件中获取方向,并添加了一个 useEffect
具有来自 moveSnake
函数的逻辑
我不知道你的项目当前的功能,但是上面的代码可以运行,并且可以移动。