useFreshCallback
Returns a stable function that delegates to the latest callback after effects run.
About
useFreshCallback avoids stale closures without changing function identity on every render. It is useful for subscriptions and timers that should stay installed while their callback reads current props or state.
Example
import { useEffect, useState } from "react";
import { useFreshCallback } from "rooks";
export default function WindowWidthLogger() {
const [label, setLabel] = useState("Window");
const reportWidth = useFreshCallback(() => {
console.log(`${label}: ${window.innerWidth}px`);
});
useEffect(() => {
window.addEventListener("resize", reportWidth);
return () => window.removeEventListener("resize", reportWidth);
}, [reportWidth]);
return (
<label>
Log label{" "}
<input
value={label}
onChange={(event) => setLabel(event.currentTarget.value)}
/>
</label>
);
}Parameters
callback: (...args: Args) => R— required function to keep fresh.
Return value
Returns (...args: Args) => R. Its identity stays stable, it forwards arguments and return values, and it calls the callback stored by the latest completed passive effect.
Behavior and lifecycle
The internal ref initially contains the first callback and is updated after every render in a passive effect. A call before that effect finishes can therefore reach the callback from the previous committed render. Errors are not intercepted; they propagate to the caller.
Compatibility and accessibility
The hook itself is platform-independent and SSR-safe. Browser access in the callback occurs only when the returned function is invoked. Accessibility depends on the event or control using it.
Related
- useFreshRef exposes the current value through
.current. - useFreshTick calls the latest void callback but does not preserve wrapper identity.