shadcn.io is an independent project built on shadcn/ui
useUnmount runs your function once, when the component unmounts. The function is stored on a ref, so the last render is the one that runs.
Use it to close a socket or drop a subscription. For a timer you also want to pause, see useTimeout. In React an empty effect list is what keeps this from running on every update.
Installation
Anatomy

Usage
import { useUnmount } from "@/hooks/use-unmount";useUnmount(() => {
connection.close();
});The hook returns nothing. The function runs once on unmount and sees the props and state from the latest render.
FAQ
Why use this instead of a useEffect cleanup?
A useEffect cleanup runs every time a dependency changes, not only when the component leaves the tree. useUnmount registers one effect with an empty dependency list, so React runs its cleanup only on unmount. The function you pass is kept on a ref that is updated during render, which means the unmount call sees the latest function even though the effect itself never re-subscribes. You do not put props in a dependency list to keep the cleanup fresh.
Does the callback see current props and state?
Yes. On every render the hook assigns your function to a ref before the effect runs. The effect closes over that ref, not over the function from the first render. When the component unmounts, the cleanup calls the function currently stored there. That function was created on the last render, so it closes over the last props and state. You do not need a manual ref for each value the cleanup wants to read.
Can I call useUnmount more than once?
Yes. Each call creates its own ref and its own effect. On unmount, React runs those cleanups. Split them when the teardowns are unrelated, such as one call that logs and another that closes a socket. They do not share a list you can edit. Keep each function small. Wrap a risky call in your own try and catch if a failure should not skip the rest of your teardown.
What if the callback throws or is not a function?
If the argument is not a function, the hook throws during render with the message that it expected a function. That happens before the effect is registered. If the function throws later, during unmount, the error propagates from the effect cleanup like any other cleanup error. The component is already gone, so a boundary above it is what can catch that error. Catch inside the callback when the teardown is allowed to fail quietly.
Does the callback run on the server?
No. The only side effect is inside useEffect, and that cleanup runs in the browser when the component unmounts. Server rendering checks that you passed a function and stores it on a ref. It does not run the cleanup. A client navigation that removes the component does. In development, Strict Mode mounts, unmounts, and mounts again, so the callback can run once before the real leave.
What does useUnmount return?
It returns nothing. There is no stop function and no flag you can read. Calling it is a registration. The argument must be a function, and the hook ignores the function return value, so returning a promise or a cleanup from your callback does not schedule more work. If you need to cancel the unmount behavior, do that inside your function with a condition, or do not call the hook. Hooks cannot be skipped behind an if.
API Reference
Parameters
fn() => void
Called once, on unmount. Anything but a function throws.
- Type
() => void











