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

React中handleKeyUp函数无法访问更新后的状态变量求助

Fixing the Stale State Issue in Your Keyup Handler

Hey there! Great first post—no worries if you're still getting the hang of things, we’ve all been there. Let’s break down why your handleKeyUp function is only seeing the initial versions of correctLetters and wrongLetters, and how to fix it.

The Root Problem

Your useEffect that adds the keyup listener has an empty dependency array ([]), which means it only runs once when the component first mounts. At that moment, the handleKeyUp function "captures" the initial state values of correctLetters, wrongLetters, and word. Even when those states update later, the event listener is still using that original version of handleKeyUp—so it can’t access the fresh state data.

The Solution

We need to make sure the event listener gets updated whenever the state or the handleKeyUp function changes. Here’s the step-by-step fix:

  1. Memoize handleKeyUp with useCallback
    This ensures the function only recreated when its dependencies (the states it relies on) change, instead of on every render.
  2. Update the useEffect dependencies
    Add handleKeyUp to the dependency array so the effect re-runs (removes the old listener and adds the new one) whenever the function updates.
  3. Add a cleanup function
    This prevents memory leaks by removing the event listener when the component unmounts or when the effect re-runs.

Modified Code

const WORDS = ['application', 'programming', 'interface', 'wizard']
const selectedWord = WORDS[Math.floor(Math.random() * WORDS.length)]

function App() {
  const [word, setWord] = useState(selectedWord)
  const [correctLetters, setCorrectLetters] = useState([])
  const [wrongLetters, setWrongLetters] = useState([])
  const [showNotification, setShowNotification] = useState(false)

  // Wrap handleKeyUp with useCallback to memoize it
  const handleKeyUp = useCallback((e) => {
    if (e.keyCode >= 65 && e.keyCode <= 90) {
      const letter = e.key
      if (word.includes(letter)) {
        if (!correctLetters.includes(letter)) {
          setCorrectLetters(letters => [...letters, letter])
        } else {
          handleNotification()
        }
      } else {
        if (!wrongLetters.includes(letter)) {
          setWrongLetters(letters => [...letters, letter])
        } else {
          handleNotification()
        }
      }
    }
  }, [word, correctLetters, wrongLetters]) // Add all dependencies here

  // Update useEffect with cleanup and correct dependencies
  useEffect(() => {
    document.addEventListener("keyup", handleKeyUp)
    
    // Cleanup: remove listener when component unmounts or effect re-runs
    return () => {
      document.removeEventListener("keyup", handleKeyUp)
    }
  }, [handleKeyUp]) // Now depend on the memoized handleKeyUp

  // Don't forget to define the handleNotification function!
  const handleNotification = () => {
    setShowNotification(true)
    // Optional: Auto-hide notification after 2 seconds
    setTimeout(() => setShowNotification(false), 2000)
  }

  // Rest of your component logic/rendering here...
}

Quick Bonus Note

You were already using the functional update form (setCorrectLetters(letters => [...letters, letter])) which is awesome—it ensures you’re always working with the most up-to-date state when making updates. The main issue was just the stale closure from the event listener, which the useCallback and updated useEffect fix perfectly.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 11:47:56