You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何我的eventListener仅在选中对应屏幕后生效一次?

问题分析与解决方案

你的代码存在三个核心问题,导致键盘切换逻辑只能生效一次:

  1. 闭包捕获旧状态:onKeydown4里直接引用的store是组件初始渲染时的闭包值,后续store更新后,事件处理函数里的store还是旧值,切换逻辑会失效。
  2. 未清理全局事件监听:进入Screen4时添加了键盘监听,但离开页面时没移除,不仅会造成内存泄漏,还可能在其他页面触发错误逻辑。
  3. useEffect依赖缺失:useEffect的依赖数组是空的,只有组件挂载时执行一次,当props.name变化(比如离开再回到Screen4),不会重新执行监听的添加逻辑。

修复后的代码如下:

// 用useCallback包裹事件函数,依赖store保证状态更新时函数能获取最新值
const onKeydown4 = useCallback((e) => {
  if (e.key === "w") {
    // 使用函数式更新,直接获取最新的store状态,规避闭包问题
    setStore(prevStore => ({
      ...prevStore, // 不要遗漏store里的其他状态属性
      bigVariant: prevStore.bigVariant === "variant_big_A" 
        ? "variant_big_B" 
        : "variant_big_A"
    }));
  }
}, [store]);

useEffect(() => {
  if (props.name === "Screen 4") {
    window.addEventListener("keydown", onKeydown4);
    // 清理函数:离开Screen4时自动移除监听
    return () => {
      window.removeEventListener("keydown", onKeydown4);
    };
  }
}, [props.name, onKeydown4]); // 补充依赖,props切换或函数更新时重新执行逻辑

return <Component {...props} />;

关键修复点说明:

  • 函数式更新setStore:通过prevStore参数获取最新状态,彻底解决闭包导致的旧值问题。
  • useCallback缓存事件函数:保证onKeydown4的引用稳定,同时依赖store,状态更新时函数会重新生成,确保能拿到最新状态。
  • useEffect清理函数:离开Screen4时自动移除全局监听,避免副作用残留。
  • 补充useEffect依赖:当props.name切换或事件函数更新时,重新执行监听的添加/移除逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:12:27