useRafState
React state hook that only updates state in the callback of requestAnimationFrame
useRafState has the same API as useState but defers state updates to the next animation frame via requestAnimationFrame. This batches rapid state changes (such as those from mouse or scroll events) into a single update per frame, reducing unnecessary re-renders and improving performance for high-frequency updates.
When to Use
- Tracking mouse position, scroll offset, or window dimensions where events fire far more often than the screen refreshes
- Smoothing out state updates from sensors or streams that produce data faster than 60fps
- Reducing render overhead for any state that changes very rapidly and is used primarily for visual output
Notes
- Browser-only:
requestAnimationFrameis not available during SSR. The hook still works, but updates will not be batched on the server. - Same API as useState: The returned tuple is
[state, setState]with the sameSetStateAction<S>signature, so it is a drop-in replacement. - Automatic cleanup: Pending animation frame requests are cancelled on unmount to prevent memory leaks.
Usage
Live Editor
function Demo() { const [state, setState] = useRafState({ x: 0, y: 0 }); useMount(() => { const onMouseMove = (event: MouseEvent) => { setState({ x: event.clientX, y: event.clientY }); }; const onTouchMove = (event: TouchEvent) => { setState({ x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY, }); }; document.addEventListener("mousemove", onMouseMove); document.addEventListener("touchmove", onTouchMove); return () => { document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("touchmove", onTouchMove); }; }); return <pre>{JSON.stringify(state, null, 2)}</pre>; };
Result
API
useRafState
Returns
readonly [S, React.Dispatch<React.SetStateAction<S>>]: A tuple with the following elements:
- the state value
- a function to update state in
requestAnimationFrame
Arguments
| Argument | Description | Type | DefaultValue |
|---|---|---|---|
| initialState | state value | S | (() => S) (Required) | - |