Skip to content

Commit daba00c

Browse files
refactor useMediaQuery hook for improved media query handling
1 parent d571cc3 commit daba00c

File tree

1 file changed

+29
-43
lines changed

1 file changed

+29
-43
lines changed
Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,40 @@
1-
import { useEffect, useState } from "react";
1+
import { useCallback, useSyncExternalStore } from "react";
22

3-
function getDevice(): "mobile" | "tablet" | "desktop" | null {
4-
if (typeof window === "undefined") return null;
3+
type MediaQuery = `(${string}:${string})`;
54

6-
return window.matchMedia("(min-width: 1024px)").matches
7-
? "desktop"
8-
: window.matchMedia("(min-width: 640px)").matches
9-
? "tablet"
10-
: "mobile";
5+
function getMediaQueryMatch(query: MediaQuery) {
6+
return window.matchMedia(query).matches;
117
}
128

13-
function getDimensions() {
14-
if (typeof window === "undefined") return null;
15-
16-
return { width: window.innerWidth, height: window.innerHeight };
9+
function addMediaQueryListener(query: MediaQuery, onChange: () => void) {
10+
const mediaQueryList = window.matchMedia(query);
11+
mediaQueryList.addEventListener("change", onChange);
12+
return function cleanup() {
13+
mediaQueryList.removeEventListener("change", onChange);
14+
};
1715
}
1816

19-
export function useMediaQuery() {
20-
const [device, setDevice] = useState<"mobile" | "tablet" | "desktop" | null>(
21-
getDevice(),
17+
function useMediaQuerySync(query: MediaQuery) {
18+
const subscribeToMediaQuery = useCallback(
19+
(onChange: () => void) => addMediaQueryListener(query, onChange),
20+
[query],
2221
);
23-
const [dimensions, setDimensions] = useState<{
24-
width: number;
25-
height: number;
26-
} | null>(getDimensions());
27-
28-
useEffect(() => {
29-
const checkDevice = () => {
30-
setDevice(getDevice());
31-
setDimensions(getDimensions());
32-
};
33-
34-
// Initial detection
35-
checkDevice();
36-
37-
// Listener for windows resize
38-
window.addEventListener("resize", checkDevice);
39-
40-
// Cleanup listener
41-
return () => {
42-
window.removeEventListener("resize", checkDevice);
43-
};
44-
}, []);
22+
const matches = useSyncExternalStore(
23+
subscribeToMediaQuery,
24+
function getSnapshot() {
25+
return getMediaQueryMatch(query);
26+
},
27+
function getServerSnapshot() {
28+
return false;
29+
},
30+
);
31+
return matches;
32+
}
4533

34+
export function useMediaQuery() {
4635
return {
47-
device,
48-
width: dimensions?.width,
49-
height: dimensions?.height,
50-
isMobile: device === "mobile",
51-
isTablet: device === "tablet",
52-
isDesktop: device === "desktop",
36+
isDesktop: useMediaQuerySync("(min-width: 1024px)"),
37+
isTablet: useMediaQuerySync("(min-width: 640px) and (max-width: 1023px)"),
38+
isMobile: useMediaQuerySync("(max-width: 639px)"),
5339
};
5440
}

0 commit comments

Comments
 (0)