usePrevious
Returns the value from the previous render. It does not cause extra re-renders.
When to use it
- Diffing props or state, for example detecting whether a number went up or down.
- Driving animations or transitions between an old and a new value.
- Running logic only when a specific value changed.
Demo
Loading demo…
Signature
interface UsePreviousOptions<T> {
initialValue: T;
}
interface UsePrevious {
<T>(value: T, options: UsePreviousOptions<T>): T;
<T>(value: T): T | undefined;
}
const usePrevious: UsePrevious;
| Parameter | Description |
|---|---|
value | The value to track. |
options.initialValue | Optional. Returned on the first render instead of undefined. |
Returns: the value from the previous render, or undefined (or
initialValue) on the first render.
Notes
- The value is recorded after each commit, so it reflects the previous render. If the component rerenders for an unrelated reason, the returned value catches up to the current one.
- To track a specific field of an object, pass that field (for example
usePrevious(user.id)) rather than the whole object.
Example
const prevCount = usePrevious(count);
const direction =
prevCount === undefined || prevCount === count
? "none"
: count > prevCount
? "up"
: "down";
Source
src/hooks/use-previous.ts
import { useEffect, useRef } from "react";
/** Options for {@link usePrevious}. */
export interface UsePreviousOptions<T> {
/** Value returned on the first render, before any previous value exists. */
initialValue: T;
}
/** Call signatures of {@link usePrevious}. */
export interface UsePrevious {
<T>(value: T, options: UsePreviousOptions<T>): T;
<T>(value: T): T | undefined;
}
/**
* Returns the value passed to the hook on the previous render.
*
* Useful for diffing props or state, detecting direction of change, or
* driving animations. It does not trigger extra re-renders: the value is
* recorded in a ref after each commit.
*
* Without `initialValue` the hook returns `undefined` on the first render.
* To track a derived value (for example `item.id`) pass that value instead of
* the whole object. Read the result while rendering or in effects.
*
* @param value - The value to track.
* @param options - Optional settings; `initialValue` is returned on the first render.
* @returns The value from the previous render.
*
* @example
* ```ts
* const prevCount = usePrevious(count);
* const direction = prevCount === undefined || count === prevCount
* ? "none"
* : count > prevCount ? "up" : "down";
* ```
*/
export const usePrevious = (<T>(
value: T,
options?: UsePreviousOptions<T>
): T | undefined => {
const ref = useRef<T | undefined>(options?.initialValue);
useEffect(() => {
ref.current = value;
});
return ref.current;
}) as UsePrevious;