@qazuor/react-hooks
Version:
A comprehensive collection of production-ready React hooks for modern web applications. Features type-safe implementations, extensive testing, and zero dependencies. Includes hooks for state management, browser APIs, user interactions, and development uti
88 lines (79 loc) • 2.94 kB
text/typescript
import { useCallback, useEffect, useRef, useState } from 'react';
interface UseWindowWidthOptions {
/** Debounce delay in milliseconds */
debounceDelay?: number;
/** Whether to start monitoring immediately */
startImmediately?: boolean;
/** Initial width to use (defaults to window.innerWidth) */
initialWidth?: number;
/** Callback when width changes */
onChange?: (width: number) => void;
}
interface UseWindowWidthReturn {
/** Current window width */
width: number;
/** Start monitoring width changes */
start: () => void;
/** Stop monitoring width changes */
stop: () => void;
}
/**
* useWindowWidth
*
* @description A hook that gets the current window width and
* updates it automatically on resize with debouncing.
* Provides methods to start and stop monitoring.
*
* @param {UseWindowWidthOptions} [options] - Optional configuration.
* @returns {UseWindowWidthReturn} - An object containing the current width and control methods.
*
* @example
* // Example of use in a functional component:
* import React from 'react';
* import { useWindowWidth } from 'my-react-hooks';
*
* function Demo() {
* const { width, start, stop } = useWindowWidth({ debounceDelay: 100 });
* return <div>El ancho de la ventana es: {width}px</div>; // Keep Spanish in example string
* }
*/
export function useWindowWidth({
debounceDelay = 250,
startImmediately = true,
initialWidth = typeof window !== 'undefined' ? window.innerWidth : 0,
onChange
}: UseWindowWidthOptions = {}): UseWindowWidthReturn {
const [width, setWidth] = useState<number>(initialWidth);
const [isMonitoring, setIsMonitoring] = useState(startImmediately);
const timeoutRef = useRef<number | null>(null);
const handleResize = useCallback(() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current);
}
timeoutRef.current = window.setTimeout(() => {
const newWidth = window.innerWidth;
setWidth(newWidth);
onChange?.(newWidth);
}, debounceDelay);
}, [debounceDelay, onChange]);
const start = useCallback(() => setIsMonitoring(true), []);
const stop = useCallback(() => setIsMonitoring(false), []);
useEffect(() => {
if (isMonitoring) {
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current);
}
};
} else {
window.removeEventListener('resize', handleResize);
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
}
}, [isMonitoring, handleResize]);
return { width, start, stop };
}