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

React中Keyup事件监听器无法获取更新后的状态

问题原因与解决方案

问题根源

你的代码触发了React的闭包陷阱:

  • useEffect的依赖数组为空,仅在组件首次挂载时执行一次,此时handleShortcutKeys函数捕获的是name的初始值("John Doe")。
  • 当你通过输入框更新name时,组件会重新渲染,但由于useEffect的依赖未变化,不会重新创建handleShortcutKeys,事件监听始终调用旧函数,拿到的自然是初始状态。

解决方案一:添加状态到依赖数组

将name加入useEffect的依赖数组,每次name更新时,useEffect会重新执行,移除旧监听并绑定新的监听函数,新函数将捕获最新的name值。

修改后的核心代码:

useEffect(() => {
  let handleShortcutKeys = (evt) => {
    if (evt.ctrlKey && evt.key === "Enter") {
      alert(name);
    }
  };
  window.addEventListener("keyup", handleShortcutKeys);
  return () => {
    window.removeEventListener("keyup", handleShortcutKeys);
  };
}, [name]); // 添加name作为依赖

解决方案二:使用useRef保存最新状态

如果不想频繁绑定/解绑事件监听,可以用useRef保存最新的name值,ref.current始终指向当前最新状态,无需依赖数组变化。

修改后的完整代码:

import "./styles.css";
import { useState, useEffect, useRef } from "react";

export default function App() {
  let [name, setName] = useState("John Doe");
  const nameRef = useRef(name);

  // 同步ref与最新状态
  useEffect(() => {
    nameRef.current = name;
  }, [name]);

  useEffect(() => {
    let handleShortcutKeys = (evt) => {
      if (evt.ctrlKey && evt.key === "Enter") {
        alert(nameRef.current); // 访问最新状态
      }
    };
    window.addEventListener("keyup", handleShortcutKeys);
    return () => {
      window.removeEventListener("keyup", handleShortcutKeys);
    };
  }, []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <input
        type="text"
        placeholder="enter something..."
        value={name}
        onChange={(evt) => setName(evt.target.value)}
      />
      <br />
      <br />
      <button onClick={() => alert(name)}>Alert Name</button>
    </div>
  );
}

方案对比

  • 方案一:实现简单,适合状态更新不频繁的场景,但每次状态变化都会重新绑定事件。
  • 方案二:仅绑定一次事件监听,性能更优,适合状态频繁更新的场景(比如在线IDE的代码编辑场景)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:39:31