React involved
Even values that need no hook can now require one.
React 19 ready, emotionally questionable
Hooks for problems nobody should have.
Technically functional React 19 hooks with reasons to exist ranging from “barely defensible” to “please just write the value directly.”
const status = useStateWithoutSetter("initial");
// There is no setter.
// status remains "initial".
// React has been involved for no reason.
Bad ideas, accurate naming
Every public hook works. Whether any of them should be called is a separate and much shorter discussion.
Even values that need no hook can now require one.
TypeScript can describe every questionable decision precisely.
Constants, browser melodrama, and intervals coexist without explanation.
Your bundler can remove the hooks you were sensible enough not to import.
More indirection, no benefit
Write 0. Use the value directly. Keep the setter. These are all excellent ways to avoid this package.
Read the fine print
Every public export, including the alternatives you should use instead.
Runs a callback repeatedly. This one is suspiciously defensible.
useInterval(callback: () => void, delay: number | null);
const [tick, setTick] = useState(0);
useInterval(() => setTick((n) => n + 1), 1000);
Calls pointer inactivity a dramatic pause because “idle” lacked theatre.
useDramaticPause(delay?: number): boolean;
const dramatic = useDramaticPause(1000);
Makes a browser tab resent visitors who briefly leave it.
useTabJealousy(options?: UseTabJealousyOptions): string | null;
const complaint = useTabJealousy();
Writes an alibi for a burst of keyboard nonsense.
useKeyMashExcuse(options?: UseKeyMashExcuseOptions): string | null;
const excuse = useKeyMashExcuse({ threshold: 4 });
Predicts absolutely nothing from how far someone scrolls.
useDoomScrollOracle(options?: UseDoomScrollOracleOptions): string | null;
const prophecy = useDoomScrollOracle({ distance: 800 });
Gives every focus change an entirely silent fanfare.
useFocusFanfare(options?: UseFocusFanfareOptions): string | null;
const fanfare = useFocusFanfare();
Treats every copy event as evidence of an unspecified crime.
useClipboardSuspicion(options?: UseClipboardSuspicionOptions): string | null;
const suspicion = useClipboardSuspicion();
Judges history traversal without knowing whether it was Back or Forward.
useBackButtonRegret(options?: UseBackButtonRegretOptions): string | null;
const regret = useBackButtonRegret();
Returns 0 through React. A reasonable person would write 0.
useZeroZero(): number;
const zero = useZeroZero();
Returns the value supplied. Using the value directly remains available.
useSameSame<T>(value: T): T;
const same = useSameSame(value);
Creates state, discards its setter, and leaves the initial value trapped forever.
useStateWithoutSetter<T>(initialValue: T): T;
const permanentlyInitial = useStateWithoutSetter("initial");
A reasonable person would use the value directly, or keep the setter. This hook should not exist.
Stores a stable ref inside another stable ref, doubling the indirection without improving the value.
useRefRef<T>(initialValue: T): RefObject<RefObject<T>>;
const refRef = useRefRef("unnecessarily deep");
const value = refRef.current.current;
A reasonable person would use useRef(initialValue). This hook should not exist.
Schedules a React effect whose entire effect is having no effect.
useEffectWithoutEffect(): void;
useEffectWithoutEffect();
A reasonable person would do nothing at all. This hook should not exist.