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

带回调函数的自定义React Hook出现闭包问题

解决React自定义Hook中闭包捕获旧props的问题

这个问题很典型——你的useKeyPress钩子因为闭包特性,导致回调函数一直捕获的是组件初始渲染时的props值。本质原因是useEffect的依赖数组为空,事件监听只在组件挂载时绑定一次,后续callback或者targetKey变化时,不会更新监听的处理函数。

下面给你两种常用的解决方案,你可以根据场景选择:

方案1:更新useEffect的依赖数组

最简单的修复方式,就是把targetKey和callback加入到useEffect的依赖数组中。这样每当这两个值发生变化时,钩子就会移除旧的事件监听,绑定新的处理函数,确保回调始终能拿到最新的props值。

修改后的钩子代码:

export default function useKeyPress(targetKey, callback) {
  const keyPressedHandler = ({ key }) => {
    if (key === targetKey && callback && typeof callback === 'function') {
      callback();
    }
  };

  useEffect(() => {
    window.addEventListener('keyup', keyPressedHandler);
    return () => {
      window.removeEventListener('keyup', keyPressedHandler);
    };
  }, [targetKey, callback]); // 添加依赖,触发监听更新
}

为什么有效?
当你的Component中isActive变化时,传入useKeyPress的箭头函数会重新创建(因为它依赖isActive),这会触发useEffect重新执行,替换掉旧的事件监听,此时新的回调就能捕获到最新的isActive值了。

方案2:用useRef保存最新回调(减少监听解绑/绑定次数)

如果你不想每次callback变化都重新绑定事件监听,可以用useRef来追踪最新的回调函数,这样事件监听只需要绑定一次(或者仅在targetKey变化时更新),同时保证触发时调用的是最新的回调。

修改后的钩子代码:

import { useEffect, useRef, useCallback } from 'react';

export default function useKeyPress(targetKey, callback) {
  // 用ref保存最新的callback引用
  const callbackRef = useRef(callback);

  // 同步最新的callback到ref
  useEffect(() => {
    callbackRef.current = callback;
  }, [callback]);

  // 用useCallback缓存处理函数,仅当targetKey变化时重新创建
  const keyPressedHandler = useCallback(({ key }) => {
    if (key === targetKey && callbackRef.current && typeof callbackRef.current === 'function') {
      callbackRef.current();
    }
  }, [targetKey]);

  useEffect(() => {
    window.addEventListener('keyup', keyPressedHandler);
    return () => {
      window.removeEventListener('keyup', keyPressedHandler);
    };
  }, [keyPressedHandler]);
}

为什么有效?

  • callbackRef会始终保存最新的回调函数,不管组件怎么重新渲染,callbackRef.current都是最新的那个。
  • useCallback确保keyPressedHandler只有在targetKey变化时才会重新创建,避免不必要的事件监听更新。

两种方案都能解决你的问题,方案1更简单直接,适合大多数场景;方案2在性能优化上更友好,尤其是当callback频繁变化但targetKey很少变化时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 17:34:06