Join our Discord Community

useUnmount

React hook for running cleanup logic when a component unmounts. Perfect for React applications requiring cleanup tasks like canceling subscriptions with Next.js integration and TypeScript support.

Loading component...

Installation

npx shadcn@latest add https://www.shadcn.io/registry/use-unmount.json
npx shadcn@latest add https://www.shadcn.io/registry/use-unmount.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/use-unmount.json
bunx shadcn@latest add https://www.shadcn.io/registry/use-unmount.json

Features

  • Unmount cleanup with automatic execution when component unmounts using useEffect
  • Function validation with runtime type checking and descriptive error messages
  • Stable reference using useRef to maintain current function reference across re-renders
  • Memory efficient with proper cleanup to prevent memory leaks and stale closures
  • TypeScript support with complete type definitions and parameter validation
  • Simple API with single function parameter for ease of use and minimal learning curve

Use Cases

This free open source React hook works well for:

  • API request cleanup - Cancel pending network requests built with Next.js and TypeScript
  • Timer cleanup - Clear intervals and timeouts using JavaScript patterns
  • Event listeners - Remove event listeners and unsubscribe from events with Tailwind CSS apps
  • Subscription cleanup - Unsubscribe from WebSocket connections and data streams
  • Local storage - Save component state to localStorage before unmounting
  • Analytics tracking - Send component usage analytics on unmount

API Reference

useUnmount

ParameterTypeDescription
fn() => voidRequired. The cleanup function to run when component unmounts

Usage Patterns

Basic Cleanup

import { useUnmount } from "@/hooks/use-unmount";

function MyComponent() {
  useUnmount(() => {
    console.log("Component is unmounting");
  });

  return <div>Hello world</div>;
}

Timer Cleanup

import { useUnmount } from "@/hooks/use-unmount";

function TimerComponent() {
  const timerId = useRef<NodeJS.Timeout>();

  useEffect(() => {
    timerId.current = setInterval(() => {
      console.log("Timer tick");
    }, 1000);
  }, []);

  useUnmount(() => {
    if (timerId.current) {
      clearInterval(timerId.current);
    }
  });

  return <div>Timer running...</div>;
}

API Request Cleanup

import { useUnmount } from "@/hooks/use-unmount";

function DataComponent() {
  const abortController = useRef(new AbortController());

  useEffect(() => {
    fetch("/api/data", {
      signal: abortController.current.signal,
    })
      .then((response) => response.json())
      .then((data) => setData(data))
      .catch((error) => {
        if (error.name !== "AbortError") {
          console.error("Fetch error:", error);
        }
      });
  }, []);

  useUnmount(() => {
    abortController.current.abort();
  });

  return <div>Loading data...</div>;
}

Event Listener Cleanup

import { useUnmount } from "@/hooks/use-unmount";

function WindowComponent() {
  useEffect(() => {
    const handleResize = () => {
      console.log("Window resized");
    };

    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  useUnmount(() => {
    console.log("Component unmounted, all listeners cleaned");
  });

  return <div>Listening to window resize</div>;
}

Implementation Notes

  • Hook validates input is a function and throws descriptive error if not
  • Uses useRef to maintain stable reference to the latest cleanup function
  • Function reference is updated on every render to ensure latest closure is used
  • Cleanup function runs only once when component unmounts (useEffect with empty deps)
  • Compatible with React 16.8+ and follows all React hooks rules and patterns
  • Does not interfere with other useEffect cleanup functions in the same component
  • Cleanup function has access to the latest component state and props when called