0 day streak
javascript / intermediate
Snippet

Hydration-Safe Media Query Hook

In Next.js, using window.matchMedia directly during initialization causes a hydration mismatch because the server doesn't have a 'window' object. This hook initializes state as false and updates it inside useEffect to ensure it only runs on the client.

snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { useState, useEffect } from 'react';
export function useMediaQuery(query: string) {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
if (media.matches !== matches) setMatches(media.matches);
const listener = () => setMatches(media.matches);
media.addEventListener('change', listener);
return () => media.removeEventListener('change', listener);
}, [query, matches]);
return matches;
}
nextjs
Breakdown
1
const [matches, setMatches] = useState(false);
Initializes with a default value to match the server-side render.
2
useEffect(() => { ... }, [query, matches]);
Runs only on the client, avoiding server-side execution errors.
3
return () => media.removeEventListener('change', listener);
Cleans up the event listener to prevent memory leaks.