Skip to main content

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;
ParameterDescription
valueThe value to track.
options.initialValueOptional. 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;