Easy

useIsMounted

Prompt

Create a custom hook useIsMounted that returns false on the initial server-side render and true after the component has mounted on the client. This lets you safely use browser-only APIs like window, document, and localStorage.

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

This hook is tiny, but it solves a real problem that comes up constantly when you're working with server-side rendering (SSR) in frameworks like Next.js.

export function useIsMounted() {
const [isMounted, setIsMounted] = useState(false);

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

return isMounted;
}

Three lines of actual logic. Here's why it works:

useEffect only runs on the client. It never runs on the server. So the flow looks like this:

  • On the server: useState(false) returns false. useEffect doesn't run. Hook returns false.
  • First render on the client: Same thing. Returns false. This matches the server's output, which keeps React happy (no hydration mismatch).
  • After the component mounts: useEffect fires, sets state to true, and React re-renders. Now the hook returns true.

When you actually need this

If you're building with Next.js (or any SSR framework), your React components first run on the server to generate HTML. The problem is that browser APIs like window, document, localStorage, and navigator don't exist on the server. If your component tries to use them, it crashes.

This hook lets you safely wait until you're on the client:

const isMounted = useIsMounted();
if (!isMounted) return <Skeleton />;
// Now safe to use window, localStorage, etc.

Why not just check typeof window?

You might think typeof window !== 'undefined' is simpler. And it does work technically. But it can cause a subtle bug: the server renders with false (no window), the client's first render sees true (window exists), and now the server and client outputs don't match. React calls this a "hydration mismatch" and warns about it.

useIsMounted avoids this because both server and client produce the same output on the first render (false). The switch to true happens in a second render, after hydration is complete. Clean and consistent.