Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 19x 19x 19x 19x 7x 7x 19x | import { useRef } from "react";
/**
* Comparator used to decide whether the tracked value changed between renders.
* Return `true` when `previous` and `current` should be considered equal (in
* which case the stored "previous" value is left untouched). Defaults to
* `Object.is`.
*/
export type UsePreviousComparator<T> = (previous: T, current: T) => boolean;
/**
* Returns the previous **distinct** value — the value from the last render in
* which it actually changed, not simply the value from the render before this
* one.
*
* On the first render there is no previous value, so it returns `undefined`.
* By default values are compared with `Object.is`, so a value that never
* changes keeps `undefined` as its "previous". This "previous distinct value"
* semantic is what change-detection logic usually wants, but it differs from a
* naive "value one render ago": if `value` is unchanged across a re-render, the
* returned previous does **not** advance.
*
* Pass a custom `isEqual` to ignore changes that are referentially different
* but semantically equal (e.g. new object literals with the same fields).
*
* @param value - The value to track
* @param isEqual - Optional equality comparator (defaults to `Object.is`)
* @returns The previous distinct value, or `undefined`
*
* @example
* ```tsx
* const [count, setCount] = useState(0);
* const prev = usePrevious(count);
* return <p>{prev} → {count}</p>;
* ```
*
* @example
* ```tsx
* // Ignore new-but-equal objects
* const prev = usePrevious(user, (a, b) => a.id === b.id);
* ```
*
* @remarks
* This tracks the previous *distinct* value (updated during render), which is
* correct under StrictMode's double-invoked render. Under concurrent rendering,
* a render React discards can still advance the stored value, so in rare cases
* the "previous" may reflect a value from an interrupted (never committed)
* render. For the common synchronous case this is not observable.
*/
export function usePrevious<T>(
value: T,
isEqual?: UsePreviousComparator<T>
): T | undefined {
const currentRef = useRef<T>(value);
const previousRef = useRef<T | undefined>(undefined);
const equal = isEqual
? isEqual(currentRef.current, value)
: Object.is(currentRef.current, value);
if (!equal) {
previousRef.current = currentRef.current;
currentRef.current = value;
}
return previousRef.current;
}
|