---
title: "useRafState – State Hook Usage & Examples"
description: "React state hook that only updates state in the callback of [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFram"
canonical: https://reactuse.com/state/userafstate/
---

# useRafState

React state hook that only updates state in the callback of [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/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**: `requestAnimationFrame` is 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 same `SetStateAction<S>` signature, so it is a drop-in replacement.
- **Automatic cleanup**: Pending animation frame requests are cancelled on unmount to prevent memory leaks.

## Usage

```tsx live
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>;
};

```

%%API%%