【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 分钟前
自定义事件发布器
java·前端·数据库
IT_陈寒38 分钟前
SpringBoot高并发优化:这5个被忽视的配置让你的QPS提升300%
前端·人工智能·后端
光影少年1 小时前
css优化都有哪些优化方案
前端·css·rust
BillKu1 小时前
npm 安装命令中关于 @ 的讲解,如:npm install @vue-office/docx vue-demi
前端·vue.js·npm
bestadc1 小时前
LeetCode 几道 Promises 和 Time 的题目
javascript·算法·leetcode
yangzhi_emo1 小时前
ES6笔记4
前端·笔记·es6
萌萌哒草头将军1 小时前
Node.js v24.8.0 新功能预览!🚀🚀🚀
前端·javascript·node.js
超人不会飛1 小时前
大模型应用 Vue H5 模板:快速落地流式交互与富文本渲染的开箱方案
前端·vue.js·github
用户458203153171 小时前
CSS无需JavaScript的交互效果实现
前端·css
影i1 小时前
在 Vue + Codemirror 中优雅回显 JSON
前端