为什么渲染每两次按键只触发一次?
Why does render triggered only once every two keydowns?
问题:
目标 : 每次我按下“W+C+N”键时,我的屏幕上会随机出现一个图像。
实际结果:图片每两次按键出现一次。例如,如果我在“W+C+N”上按 4 次,只会出现 2 个新图像。
我试过/猜测问题出在哪里:
滥用我的useEffect
,它要么来自:
- 对 removeEventListener 方法的误解,它是否“禁用”了我的 handleKey 函数中的设置坐标?
- 未指定正确的依赖项 [handleKey]:handleKey 功能由按键激活并更改新坐标。所以每次我传递一个新坐标时重新渲染似乎是正确的
- VS 代码警告:“'handleKey”函数使 useState Hook 的依赖项在每次渲染时都会发生变化。将它移到 useEffect 回调中。”我试过了,但它不再起作用了。
我的实际代码
import egg from "./logo.png";
import { useState, useEffect } from "react";
function App() {
let map = []; //array of keys to store
const [coordinates, setcoordinates] = useState([]); //array of image coordinates
const handleKey = (event) => {
onkeydown = onkeyup = function (event) {
map[event.keyCode] = event.type === "keydown";
};
//random image coordinates
if (map[87] && map[67] && map[78]) {
const newCoordinates = [...coordinates];
let random_left = Math.floor(Math.random() * window.innerWidth);
let random_top = Math.floor(Math.random() * window.innerHeight);
newCoordinates.push({ left: random_left, top: random_top });
setcoordinates(newCoordinates);
}
};
useEffect(() => {
window.addEventListener("keypress", handleKey);
return () => {
window.removeEventListener("keypress", handleKey);
};
}, [handleKey]);
return (
<div className="App">
<img src={egg} alt="o easter egg" />
<h1>Rocambole</h1>
<h2>Good luck!</h2>
{console.log(coordinates)}
{coordinates.map((item, index) => {
return (
<img
key={index}
src={egg}
alt="egg"
className="newImg"
style={{ top: `${item.top}px`, left: `${item.left}px` }}
/>
);
})}
</div>
);
}
export default App;
尝试用一个函数更新状态,这样你就可以确保注册在内存中的事件侦听器每次都获得新鲜的状态,并且还将函数handleKey
移到useEffect
中:
import egg from "./logo.png";
import { useState, useEffect } from "react";
function App() {
let map = []; //array of keys to store
const [coordinates, setcoordinates] = useState([]); //array of image coordinates
useEffect(() => {
const handleKey = (event) => {
onkeydown = onkeyup = function (event) {
map[event.keyCode] = event.type === "keydown";
};
//random image coordinates
if (map[87] && map[67] && map[78]) {
let random_left = Math.floor(Math.random() * window.innerWidth);
let random_top = Math.floor(Math.random() * window.innerHeight);
setcoordinates(coordinates =>[...coordinates, { left: random_left, top: random_top }]);
}
};
window.addEventListener("keypress", handleKey);
return () => {
window.removeEventListener("keypress", handleKey);
};
}, []);
return (
<div className="App">
<img src={egg} alt="o easter egg" />
<h1>Rocambole</h1>
<h2>Good luck!</h2>
{console.log(coordinates)}
{coordinates.map((item, index) => {
return (
<img
key={index}
src={egg}
alt="egg"
className="newImg"
style={{ top: `${item.top}px`, left: `${item.left}px` }}
/>
);
})}
</div>
);
}
export default App;
问题:
目标 : 每次我按下“W+C+N”键时,我的屏幕上会随机出现一个图像。
实际结果:图片每两次按键出现一次。例如,如果我在“W+C+N”上按 4 次,只会出现 2 个新图像。
我试过/猜测问题出在哪里:
滥用我的useEffect
,它要么来自:
- 对 removeEventListener 方法的误解,它是否“禁用”了我的 handleKey 函数中的设置坐标?
- 未指定正确的依赖项 [handleKey]:handleKey 功能由按键激活并更改新坐标。所以每次我传递一个新坐标时重新渲染似乎是正确的
- VS 代码警告:“'handleKey”函数使 useState Hook 的依赖项在每次渲染时都会发生变化。将它移到 useEffect 回调中。”我试过了,但它不再起作用了。
我的实际代码
import egg from "./logo.png";
import { useState, useEffect } from "react";
function App() {
let map = []; //array of keys to store
const [coordinates, setcoordinates] = useState([]); //array of image coordinates
const handleKey = (event) => {
onkeydown = onkeyup = function (event) {
map[event.keyCode] = event.type === "keydown";
};
//random image coordinates
if (map[87] && map[67] && map[78]) {
const newCoordinates = [...coordinates];
let random_left = Math.floor(Math.random() * window.innerWidth);
let random_top = Math.floor(Math.random() * window.innerHeight);
newCoordinates.push({ left: random_left, top: random_top });
setcoordinates(newCoordinates);
}
};
useEffect(() => {
window.addEventListener("keypress", handleKey);
return () => {
window.removeEventListener("keypress", handleKey);
};
}, [handleKey]);
return (
<div className="App">
<img src={egg} alt="o easter egg" />
<h1>Rocambole</h1>
<h2>Good luck!</h2>
{console.log(coordinates)}
{coordinates.map((item, index) => {
return (
<img
key={index}
src={egg}
alt="egg"
className="newImg"
style={{ top: `${item.top}px`, left: `${item.left}px` }}
/>
);
})}
</div>
);
}
export default App;
尝试用一个函数更新状态,这样你就可以确保注册在内存中的事件侦听器每次都获得新鲜的状态,并且还将函数handleKey
移到useEffect
中:
import egg from "./logo.png";
import { useState, useEffect } from "react";
function App() {
let map = []; //array of keys to store
const [coordinates, setcoordinates] = useState([]); //array of image coordinates
useEffect(() => {
const handleKey = (event) => {
onkeydown = onkeyup = function (event) {
map[event.keyCode] = event.type === "keydown";
};
//random image coordinates
if (map[87] && map[67] && map[78]) {
let random_left = Math.floor(Math.random() * window.innerWidth);
let random_top = Math.floor(Math.random() * window.innerHeight);
setcoordinates(coordinates =>[...coordinates, { left: random_left, top: random_top }]);
}
};
window.addEventListener("keypress", handleKey);
return () => {
window.removeEventListener("keypress", handleKey);
};
}, []);
return (
<div className="App">
<img src={egg} alt="o easter egg" />
<h1>Rocambole</h1>
<h2>Good luck!</h2>
{console.log(coordinates)}
{coordinates.map((item, index) => {
return (
<img
key={index}
src={egg}
alt="egg"
className="newImg"
style={{ top: `${item.top}px`, left: `${item.left}px` }}
/>
);
})}
</div>
);
}
export default App;