code-share/hooks/useBreakpoint.ts

58 lines
1.4 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from "react";
export const breakpoints = {
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
"2xl": 1536,
};
export type Breakpoint = keyof typeof breakpoints;
export const breakpointKeys = Object.keys(breakpoints);
export const breakpointValues = Object.values(breakpoints);
export const useBreakpoint = (onChange?: (breakpoint: number) => void) => {
const prevRef = useRef<number>(0);
const [curBreakpoint, setBreakpoint] = useState<number>(
getScreenBreakpoint()
);
const onResize = useCallback(() => {
const breakpointIdx = getScreenBreakpoint();
if (breakpointIdx >= 0 && prevRef.current !== breakpointIdx) {
if (onChange) {
onChange(breakpointIdx);
} else {
setBreakpoint(breakpointIdx);
}
prevRef.current = breakpointIdx;
}
}, [onChange]);
useEffect(() => {
window.addEventListener("resize", onResize);
onResize();
return () => {
window.removeEventListener("resize", onResize);
};
}, [onResize]);
const breakpoint = breakpointKeys[curBreakpoint];
return [curBreakpoint, breakpoint] as [number, Breakpoint];
};
export function getScreenBreakpoint() {
const width = typeof window !== "undefined" ? window.innerWidth : 0;
let breakpointIdx = breakpointValues.findIndex((i) => width <= i);
if (breakpointIdx < 0) {
breakpointIdx = breakpointKeys.length - 1;
}
return breakpointIdx;
}