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
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.