You need to enable JavaScript to run this app. React使用useState处理键盘事件时keyup将press数组重置为空问题
优惠活动
大模型
产品
解决方案
定价
更多

React使用useState处理键盘事件时keyup将press数组重置为空问题

问题原因

你遇到的是React Hook的闭包陷阱问题:

  • 你给useEffect传的依赖数组是空数组,所以这个副作用只会在组件首次渲染时执行一次,绑定的keyup、keydown函数都是首次渲染时创建的版本
  • 首次渲染时press状态是初始的空数组,这个值会被闭包捕获,后续无论press怎么更新,你绑定的keyup函数里访问到的press永远是空数组,所以filter之后返回的还是空数组,表现就是每次keyup都会把press清空。

解决方案

最简单的修改方式是把keyUp里的状态更新也改成和keyDown一样的函数式更新写法,直接从回调参数里拿到最新的状态值,不需要依赖闭包中的press:

const keyUp = (e) => {
  setPress((oldArr) => oldArr.filter((key) => key !== e.key));
};

这种方案不需要修改useEffect的依赖,也不会出现闭包问题,性能最优。

如果要保持你原来的keyUp写法,就需要把press和两个事件处理函数都加到useEffect的依赖数组里,每次press变化时重新绑定事件监听:

useEffect(() => {
  window.addEventListener("keydown", keyDown);
  window.addEventListener("keyup", keyUp);
  return function cleanup() {
    window.removeEventListener("keydown", keyDown);
    window.removeEventListener("keyup", keyUp);
  };
}, [press, keyDown, keyUp]);

不过这种写法会频繁绑定解绑事件,性能不如第一种方案。

可选优化

可以在keyDown里加去重判断,避免同一个按键被重复添加到press数组里:

const keyDown = (e) => {
  if (e.repeat) return;
  setPress((oldArr) => {
    if (oldArr.includes(e.key)) return oldArr;
    return [...oldArr, e.key];
  });
};

内容的提问来源于stack exchange,提问作者Dusttt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 14:51:00