29 lines
724 B
TypeScript
29 lines
724 B
TypeScript
import { useLayoutEffect, useState } from "react"
|
|
|
|
/** matchMedia with rAF batching — avoids resize storms re-rendering every pixel. */
|
|
export function useMatchMedia(query: string): boolean {
|
|
const [matches, setMatches] = useState(false)
|
|
|
|
useLayoutEffect(() => {
|
|
const mql = window.matchMedia(query)
|
|
let raf = 0
|
|
|
|
const sync = () => {
|
|
cancelAnimationFrame(raf)
|
|
raf = requestAnimationFrame(() => {
|
|
const next = mql.matches
|
|
setMatches((prev) => (prev === next ? prev : next))
|
|
})
|
|
}
|
|
|
|
sync()
|
|
mql.addEventListener("change", sync)
|
|
return () => {
|
|
mql.removeEventListener("change", sync)
|
|
cancelAnimationFrame(raf)
|
|
}
|
|
}, [query])
|
|
|
|
return matches
|
|
}
|