Skip to main content

useIsClient vs useIsMounted

tip

useIsClient is primarily for handling SSR scenarios, while useIsMounted is for managing component lifecycle and preventing memory leaks or updates after unmounting.

Timing and Purposeโ€‹

  • useIsClient specifically tells you if the code is running in a browser vs server environment
  • useIsMounted tells you if a component is currently mounted in the DOM

Implementationโ€‹

  • useIsClient uses useState directly and only sets to true once
  • useIsMounted uses useRef and returns a callback function that checks the ref

Return Value

  • useIsClient returns a boolean directly
  • useIsMounted returns a function that returns a boolean

Here are scenarios where they would differ:

function Example() {
const isClient = useIsClient()
const isMounted = useIsMounted()

// Scenario 1: Initial Server-Side Rendering
console.log(isClient) // false during SSR, true after hydration
console.log(isMounted()) // true in both cases

// Scenario 2: Component Unmounting
useEffect(() => {
const timer = setTimeout(() => {
console.log(isClient) // true (doesn't change)
console.log(isMounted()) // false (component unmounted)
}, 1000)

return () => clearTimeout(timer)
}, [])

return null
}

Server-Side Renderingโ€‹

  • useIsClient will be false during SSR and initial render, then true after hydration
  • useIsMounted will be true as soon as the component mounts, regardless of SSR

Component Lifecycleโ€‹

  • useIsClient stays true once set, even if the component unmounts
  • useIsMounted becomes false when the component unmounts

Race Conditionsโ€‹

  • useIsClient is better for conditional rendering based on client/server environment
  • useIsMounted is better for preventing state updates after unmounting
// Example where `useIsMounted` is more appropriate
function DataFetcher() {
const isMounted = useIsMounted()

useEffect(() => {
fetchData().then((data) => {
// Prevents memory leak and updates after unmount
if (isMounted()) {
setData(data)
}
})
}, [])
}
// Example where `useIsClient` is more appropriate
function BrowserFeature() {
const isClient = useIsClient()

// Only renders browser-specific features after hydration
return isClient ? <WindowSizeDisplay /> : null
}