【react实战】如何实现监听窗口大小变化

在日常开发场景中,监听窗口变化是一个比较常见又很重要的业务功能,其实实现起来也很简单,今天就来记录一下具体的实现以及注意事项。

实现思路

在 React 中,可以通过监听 window 的 resize 事件来检测可视区域(viewport)的宽度变化。

其中实现的关键为:

  • window.innerWidth:获取浏览器可视区域的宽度
  • window 的 resize 事件:监听窗口大小的变化,但要注意防抖,避免触发性能问题。虽然 useEffect 只执行两次,但它注册的 resize 事件回调会在每次窗口变化时触发,而这个触发频率可能极高
  • 在组件销毁时正确清理监听器,移除 resize 事件监听,避免内存泄漏。

具体实现

js 复制代码
import React, { useEffect, useState } from 'react';

export default function ViewportWidthTracker() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
  // 监听窗口大小变化
  let timeoutId = null;
  const handleResize = () => {
    // 每次触发 resize 时清除之前的定时器
    clearTimeout(timeoutId);
    // 设置新的定时器,延迟 150ms 执行
    timeoutId = setTimeout(() => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    }, 150);
  };

    window.addEventListener('resize', handleResize);

    // 清理监听器
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []); // 空依赖数组确保只在组件挂载和卸载时运行

  return (
    <div>
      <h1>当前可视区域宽度: {width}px</h1>
    </div>
  );
}

注意事项

  1. SSR 环境问题:在服务端渲染(如 Next.js)中,window 对象不存在。可通过条件判断避免错误
js 复制代码
useEffect(() => {
 if (typeof window === 'undefined') return;
 // 监听逻辑
}, []);
  1. 组件卸载时清理:必须在 componentWillUnmount 或 useEffect 返回的清理函数中移除事件监听,防止内存泄漏。

封装自定义 hook

这个场景比较常见,可以封装为自己的 hook,方便后续调用。

js 复制代码
import { useState, useEffect } from 'react';

function useWindowSize() {
  const [size, setSize] = useState({ width: 0, height: 0 });

  useEffect(() => {
  	// 监听窗口大小变化
  let timeoutId = null;
  const updateSize = () => {
    // 每次触发 resize 时清除之前的定时器
    clearTimeout(timeoutId);
    // 设置新的定时器,延迟 150ms 执行
    timeoutId = setTimeout(() => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    }, 150);
  };
    
    window.addEventListener('resize', updateSize);
    updateSize();
    
    return () => window.removeEventListener('resize', updateSize);
  }, []);

  return size;
}

// 使用自定义 Hook
function MyComponent() {
  const size = useWindowSize();
  
  return (
    <div>
      当前窗口: {size.width} x {size.height}
    </div>
  );
}
相关推荐
风止何安啊1 分钟前
用 10 行代码就能当 “服务器老板”+“网络小偷”+“文件管家”?Node.js:别不信!
前端·javascript·node.js
昨晚我输给了一辆AE862 分钟前
react-hook-form 初始化值为异步获取的数据的最佳实践
前端·react.js·强化学习
PieroPC4 分钟前
NiceGUI 内置Material Design图标库
前端
Cache技术分享4 分钟前
276. Java Stream API - 使用 flatMap 和 mapMulti 清理数据并转换类型
前端·后端
inferno5 分钟前
CSS 基础(第一部分)
前端·css
m0_611349319 分钟前
什么是副作用(Side Effects)
开发语言·前端·javascript
狗头大军之江苏分军9 分钟前
她在结婚那天离开了:我们该重新谈谈“结婚这件事”
前端·后端
消失的旧时光-19439 分钟前
从命令式跳转到声明式路由:前端、Android、Flutter 的一次统一演进
android·前端·flutter·状态模式
icestone_kai15 分钟前
ngix开启跨域
前端
咸虾米_16 分钟前
uniapp使用history路由模式打包上线到前端网页托管的注意事项
前端·uni-app·vue3·unicloud·前端网页托管