usePreviousDistinct
React hook that returns the last distinct (truly changed) value.
Made by lucasCurrentCrimson
Prev distinct—
import usePreviousDistinct from "@/components/targetblank/hooks/use-previous-distinct";
import { Button } from "@/components/ui/button";
import { useState } from "react";
const COLORS = ["Crimson", "Cobalt", "Emerald", "Amber", "Violet"];
export default function PreviousDistinctDemo() {
const [index, setIndex] = useState(0);
const current = COLORS[index];
const previous = usePreviousDistinct(current);
function next() {
setIndex((i) => (i + 1) % COLORS.length);
}
function same() {
setIndex((i) => i); // triggers re-render but same value
}
return (
<div className="flex flex-col gap-5 w-[360px]">
<div className="flex flex-col gap-2">
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground w-24">Current</span>
<span className="text-sm font-medium px-2 py-0.5 rounded bg-foreground text-background">
{current}
</span>
</div>
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground w-24">
Prev distinct
</span>
<span className="text-sm font-medium px-2 py-0.5 rounded bg-muted border border-border">
{previous ?? "—"}
</span>
</div>
</div>
<div className="flex gap-2">
<Button size="sm" onClick={next}>
Next color
</Button>
<Button size="sm" variant="outline" onClick={same}>
Re-render (same)
</Button>
</div>
</div>
);
}Installation
Install the following dependencies:
Copy and paste the following code into your project:
import * as React from "react";
interface UsePreviousDistinctOptions<T> {
isEqual?: (a: T, b: T) => boolean;
}
function defaultIsEqual<T>(a: T, b: T): boolean {
return a === b;
}
function usePreviousDistinct<T>(
value: T,
options?: UsePreviousDistinctOptions<T>,
): T | undefined {
const isEqual = options?.isEqual ?? defaultIsEqual;
const previousRef = React.useRef<T | undefined>(undefined);
const currentRef = React.useRef<T>(value);
if (!isEqual(currentRef.current, value)) {
previousRef.current = currentRef.current;
currentRef.current = value;
}
return previousRef.current;
}
export default usePreviousDistinct;Update the import paths to match your project setup.
Usage
const previous = usePreviousDistinct(status);
// With custom equality
const previous = usePreviousDistinct(value, {
isEqual: (a, b) => a.id === b.id,
});Props
| Prop | Type | Default |
|---|---|---|
isEqual? | (a: T, b: T) => boolean | - |
value | T | - |