useIsMounted

Easy

Prompt

Create a custom React hook called useIsMounted that determines if a component has been mounted to the DOM. This is particularly useful in server-side rendered (SSR) applications.

This hook helps developers distinguish between server-side and client-side rendering, allowing them to safely use client/browser only APIs like window, document, localStorage, etc.

Requirements

The hook should return a boolean indicating whether the component has mounted

Example

function ClientOnlyComponent() {
const isMounted = useIsMounted();

if (!isMounted) {
return null; // Don't render anything during SSR
}

return (
<div>
This component only renders on the client side!
{/* Now it's safe to access window, document, localStorage, etc. */}
</div>
);
}

Playground

Hint 1

Use useState to create a state variable that will track whether the component has mounted:

const [isMounted, setIsMounted] = useState(false);
Hint 2

Use useEffect with an empty dependency array to run code only after the first render is complete (i.e., when the component has mounted):

useEffect(() => {
// This code only runs on the client after the first render
}, []);

Solution

Explanation

The useIsMounted hook is a simple yet powerful tool for managing the differences between server-side and client-side rendering in React applications. Let's break down how it works:

First, we create a state variable using the useState hook to track whether the component has mounted:

const [isMounted, setIsMounted] = useState(false);

We initialize the state to false, assuming that when the component first renders (which could be on the server), it has not yet mounted to the DOM.

Next, we use the useEffect hook to update this state once the component has actually mounted:

useEffect(() => {
setIsMounted(true);
}, []);

The empty dependency array [] ensures that this effect only runs once, immediately after the component's first render is committed to the DOM. This effect will never run during server-side rendering since useEffect callbacks are only executed on the client.

Finally, we return the boolean state:

return isMounted;

During server-side rendering, this hook will always return false. On the client, it will return false for the first render, then true for all subsequent renders.

Why This Pattern Matters

This pattern is particularly important for server-side rendered (SSR) applications built with frameworks like Next.js. In SSR, your React components run in two different environments:

  1. First on the server to generate the initial HTML
  2. Then on the client to "hydrate" that HTML with event listeners and React's reconciliation

During server rendering, browser APIs like window, document, localStorage, and many others are not available. If you try to access them, your application will crash. The useIsMounted hook provides a safe way to conditionally render components that rely on browser-only APIs.

Using With Client-Only Hooks and APIs

The useIsMounted hook is especially useful for safely using other hooks that depend on browser APIs, such as:

  • useMediaQuery (which uses window.matchMedia)
  • useLocalStorage (which uses window.localStorage)
  • useWindowSize (which depends on window dimensions)
  • Third-party hooks that use browser-specific features

Instead of having numerous checks for browser availability throughout your code, you can use this pattern:

function MyComponent() {
const isMounted = useIsMounted();

// Only run the client-specific hooks when mounted
const theme = isMounted ? useLocalStorage('theme', 'light') : ['light', () => {}];
const isMobile = isMounted ? useMediaQuery('(max-width: 768px)') : false;

// Render responsibly based on mounting state
if (!isMounted) {
return <FallbackComponent />; // A simple placeholder during SSR
}

return (
// Component with full client-side functionality
);
}

Avoiding Common Pitfalls

Some developers attempt to detect server vs. client environments by directly checking for the existence of browser APIs:

// 🚫 Bad practice
const isBrowser = typeof window !== 'undefined';

While this works technically, it can lead to subtle bugs due to "hydration mismatches" between server and client renders. React expects the initial client render to produce the same UI as what the server rendered; otherwise, it warns about a "hydration mismatch."

Using the useIsMounted hook forces components to render consistently across environments while still providing a way to perform client-only logic after mounting.

00:00