React useEvent Hook: Stable Callbacks Without Stale Closures (2026)
Every React developer eventually meets the same fork in the road. You write an event handler that reads state, pass it to a child or an effect, and now you must choose: leave it as a plain inline function and watch every render create a new reference — breaking React.memo , re-running effects, re-subscribing listeners — or wrap it in useCallback and start playing dependency-array whack-a-mole, where one forgotten dependency means the handler sees state from three renders ago. That second failure mode has a name — the stale closure — and it's arguably the most common React bug in production code. The fix has a name too: useEvent , proposed in an official React RFC in 2022 , and available today as useEvent in @reactuses/core . It gives you a function whose identity never changes across renders but whose body always sees the latest state and props . Both halves of the fork, no trade-off. This post covers the API, the three-line implementation trick that makes it work, how it compares to useCallback and to React 19.2's built-in useEffectEvent , real patterns, and the one rule you must respect (don't call it during render). TypeScript-first. The Problem in Thirty Seconds Here's the bug factory. A chat component sends a heartbeat with the current draft text: function Composer ({ roomId }: { roomId : string }) { const [ draft , setDraft ] = useState ( '' ); useEffect (() => { const id = setInterval (() => { sendHeartbeat ( roomId , draft ); // ⚠️ which draft? }, 3000 ); return () => clearInterval ( id ); }, [ roomId ]); // draft intentionally omitted — we don't want to reset the timer return < textarea value = { draft } onChange = { e => setDraft ( e . target . value ) } />; } The interval closes over the draft that existed when the effect ran — the empty string. Every heartbeat sends '' forever. Add draft to the dependency array and the closure is fresh, but now the interval tears down and restarts on every keystroke . useCallback doesn't help: it has the exact same depen