useLatest
Returns a stable ref that always holds the latest value, so long-lived closures can read fresh props, state or callbacks without stale captures.
When to use it
- Calling the latest callback from a timer, event listener or async handler without re-subscribing.
- Keeping effects with stable dependencies while still reading current values.
Demo
Click the button, then open the Console tab: the interval is created once but always logs the latest count.
Loading demo…
Signature
function useLatest<T>(value: T): { readonly current: T };
Returns: a ref whose current is the latest value. It is synchronized
after each commit, so read it inside callbacks or effects, not during render.
Example
const onTickRef = useLatest(onTick);
useEffect(() => {
const id = setInterval(() => onTickRef.current(), 1000);
return () => clearInterval(id);
}, [onTickRef]);
Source
src/hooks/use-latest.ts
import { useEffect, useRef } from "react";
/**
* Returns a ref that always holds the latest value passed to the hook.
*
* Useful for reading up-to-date props, state or callbacks from long-lived
* closures (timers, event listeners, async callbacks, effects with empty
* dependency arrays) without re-subscribing or capturing stale values.
*
* The ref is synchronized in an effect, so it is updated after each commit
* rather than during render. Read `ref.current` inside callbacks or effects,
* not while rendering.
*
* @param value - The value to keep in the ref.
* @returns A stable ref object whose `current` is the latest value.
*
* @example
* ```ts
* const onTickRef = useLatest(onTick);
*
* useEffect(() => {
* const id = setInterval(() => onTickRef.current(), 1000);
* return () => clearInterval(id);
* }, [onTickRef]);
* ```
*/
export const useLatest = <T>(value: T): { readonly current: T } => {
const ref = useRef(value);
useEffect(() => {
ref.current = value;
});
return ref;
};