Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
import { useState, useEffect, useCallback, useRef } from "react";
interface WindowSize {
width: number;
height: number;
}
interface UseWindowSizeOptions {
/** Retraso de debounce en ms. Predeterminado: 100 */
debounceDelay?: number;
/** Tamaño inicial para SSR. Predeterminado: { width: 0, height: 0 } */
initialSize?: WindowSize;
}
function useWindowSize(options: UseWindowSizeOptions = {}): WindowSize {
const {
debounceDelay = 100,
initialSize = { width: 0, height: 0 },
} = options;
const [size, setSize] = useState<WindowSize>(() => {
if (typeof window === "undefined") return initialSize;
return {
width: window.innerWidth,
height: window.innerHeight,
};
});
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
if (typeof window === "undefined") return;
const handleResize = () => {
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
timerRef.current = null;
}, debounceDelay);
};
// Establecer tamaño inicial al montarse
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
if (timerRef.current) clearTimeout(timerRef.current);
};
}, [debounceDelay]);
return size;
}Cuándo usarlo: Necesitas dimensiones de ventana en JavaScript para cálculos de diseño responsivo, dimensionamiento de canvas, listas virtualizadas o renderizado condicional que las media queries de CSS no pueden manejar.
"use client";
function ResponsiveLayout() {
const { width, height } = useWindowSize();
const columns = width >= 1024 ? 3 : width >= 640 ? 2 : 1;
return (
<div>
<p>
Ventana: {width} x {height}
</p>
<div
style={{
display: "grid",
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: 16,
}}
>
{Array.from({ length: 6 }, (_, i) => (
<div
key={i}
style={{
padding: 24,
background: "#f5f5f5",
borderRadius: 8,
textAlign: "center",
}}
>
Tarjeta {i + 1}
</div>
))}
</div>
</div>
);
}
function CanvasSizer() {
const { width } = useWindowSize({ debounceDelay: 200 });
const canvasWidth = Math.min(width - 32, 800);
const canvasHeight = canvasWidth * 0.5625; // 16:9
return (
<canvas
width={canvasWidth}
height={canvasHeight}
style={{ border: "1px solid #ccc" }}
/>
);
}Qué demuestra esto:
useState lee window.innerWidth y window.innerHeight solo en el cliente, retrocediendo a initialSize durante SSR.setTimeout colapsa eventos de cambio de tamaño rápidos en una única actualización de estado, previniendo jank.| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
debounceDelay | number | 100 | Milisegundos para debounce de eventos de cambio de tamaño |
initialSize | { width, height } | { width: 0, height: 0 } | Tamaño retornado durante SSR |
| Retorno | Tipo | Descripción |
|---|---|---|
width | number | window.innerWidth actual |
height | number | window.innerHeight actual |
Sin debounce: Para actualizaciones inmediatas (p. ej., vistas previas de cambio de tamaño por arrastre), establece debounceDelay: 0 o elimina setTimeout:
const size = useWindowSize({ debounceDelay: 0 });Con orientación: Detecta paisaje vs. retrato:
function useOrientation() {
const { width, height } = useWindowSize();
return width > height ? "landscape" : "portrait";
}Tamaño del documento (altura de desplazamiento): Rastrea la altura total del documento en lugar del viewport:
// Dentro del manejador de cambio de tamaño:
setSize({
width: document.documentElement.scrollWidth,
height: document.documentElement.scrollHeight,
});WindowSize se exporta para que los consumidores puedan escribir su propio estado o props.{ width: number; height: number }.initialSize (0x0), pero el cliente se actualiza inmediatamente a dimensiones reales. Solución: Esto causa un cambio de diseño en la primera renderización. Para diseños críticos, prefiere media queries de CSS o proporciona una estimación razonable de initialSize.debounceDelay según sea necesario.window.visualViewport si necesitas distinguir el teclado del cambio de tamaño.window.innerWidth refleja el tamaño del iframe, no de la ventana padre. Solución: Usa parent.window si la política entre orígenes lo permite, o pasa el tamaño como prop.| Paquete | Nombre del Hook | Notas |
|---|---|---|
usehooks-ts | useWindowSize | Sin debounce incorporado |
@uidotdev/usehooks | useWindowSize | Implementación mínima |
ahooks | useSize | Rastrea cualquier elemento, no solo la ventana |
react-use | useWindowSize | Incluye valores predeterminados del lado del servidor |
@react-hook/window-size | useWindowSize | Variante limitada disponible |
Sin debounce, cada píxel de un arrastre de cambio de tamaño dispara una actualización de estado y re-renderización. El debounce incorporado colapsa eventos rápidos en una única actualización, previniendo jank y re-renderizaciones innecesarias.
Establece debounceDelay a 0:
const size = useWindowSize({ debounceDelay: 0 });Esto aún usa setTimeout(..., 0) que se aplaza al siguiente tick. Para actualizaciones verdaderamente sincrónicas, elimina setTimeout del hook.
initialSize proporciona las dimensiones retornadas durante SSR (predeterminado: { width: 0, height: 0 }).{ width: 1024, height: 768 }) para reducir el cambio de diseño.El componente puede haber sido desmontado y remontado mientras la ventana fue redimensionada. El conjunto inmediato asegura que el estado sea correcto incluso si ningún evento de cambio de tamaño se dispara después del montaje.
initialSize realista que coincida con tu viewport más común.useMediaQuery para verificaciones de punto de corte booleanas que puedan tolerar el breve destello.En navegadores móviles, el teclado virtual redimensiona el viewport. El hook se dispara en cualquier cambio de tamaño, incluyendo apertura/cierre del teclado. Usa la API window.visualViewport para distinguir eventos del teclado de cambios reales de ventana.
useWindowSize retorna valores exactos en píxeles (width, height).useMediaQuery retorna un booleano para un punto de corte específico.useWindowSize cuando necesitas cálculos (p. ej., dimensionamiento de canvas, conteos de columnas).useMediaQuery cuando solo necesitas un toggle booleano.Sí. Reemplaza window.innerWidth/Height con document.documentElement.scrollWidth/Height dentro del manejador de cambio de tamaño. Esto da el tamaño total del documento incluyendo overflow.
El hook retorna WindowSize, que es { width: number; height: number }. La interfaz se exporta para que los consumidores puedan usarla para sus propios tipos de props o state.
function useOrientation(): "landscape" | "portrait" {
const { width, height } = useWindowSize();
return width > height ? "landscape" : "portrait";
}Revisado por Chris St. John·Última actualización: 10 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥