You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React.js中window.resize事件使用问题:快速缩小时位置异常

React中正确使用window resize事件并解决快速缩放异常问题

你的代码能正常运行,但快速缩小窗口时出现位置异常,核心问题是resize事件触发过于频繁,导致状态更新和DOM尺寸不同步,加上没有正确管理事件监听的生命周期,才会出现异常。下面给出两种解决方案:

方案一:给resize事件添加防抖+规范生命周期管理

防抖可以限制短时间内的状态更新频率,确保只在用户停止缩放后才获取最新的DOM尺寸,同时在组件卸载时移除监听,避免内存泄漏。

完整代码示例:

import { useState, useEffect, useRef, useCallback } from 'react';

// 防抖工具函数:延迟执行回调,避免频繁触发
const debounce = (func, delay) => {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

function YourComponent() {
  const [size, setSize] = useState(0);
  const nameInput = useRef(null);

  // 用useCallback保证回调引用稳定,避免重复绑定监听
  const handleResize = useCallback(debounce(() => {
    if (nameInput.current) {
      setSize(Math.ceil(nameInput.current.offsetWidth));
    }
  }, 100), []); // 100ms可根据需求调整,数值越小响应越快,越大越稳定

  useEffect(() => {
    // 绑定resize监听
    window.addEventListener('resize', handleResize);
    // 组件卸载时移除监听,防止无效回调
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, [handleResize]);

  // 组件初始化时先获取一次初始尺寸
  useEffect(() => {
    if (nameInput.current) {
      setSize(Math.ceil(nameInput.current.offsetWidth));
    }
  }, []);

  return (
    <input ref={nameInput} type="text" placeholder="输入名称" />
  );
}

方案二:使用ResizeObserver API(更精准)

如果你的需求是监听nameInput元素本身的尺寸变化,而非整个窗口的缩放,推荐使用专门的ResizeObserver API,它能直接监听元素的尺寸变化,比window resize更精准,性能也更好。

完整代码示例:

import { useState, useEffect, useRef } from 'react';

function YourComponent() {
  const [size, setSize] = useState(0);
  const nameInput = useRef(null);

  useEffect(() => {
    const inputElement = nameInput.current;
    if (!inputElement) return;

    // 创建ResizeObserver实例,监听元素尺寸变化
    const resizeObserver = new ResizeObserver((entries) => {
      entries.forEach(entry => {
        setSize(Math.ceil(entry.contentRect.width));
      });
    });

    // 开始监听目标元素
    resizeObserver.observe(inputElement);

    // 组件卸载时停止监听
    return () => {
      resizeObserver.unobserve(inputElement);
      resizeObserver.disconnect();
    };
  }, []);

  return (
    <input ref={nameInput} type="text" placeholder="输入名称" />
  );
}

为什么能解决快速缩放异常?

原代码中resize事件每秒会触发几十次,React的状态更新是异步的,快速触发时,前一次的DOM更新还没完成,后一次就去获取offsetWidth,拿到的是旧尺寸,导致位置异常。防抖函数会等到缩放停止后再执行回调,此时DOM已经完成重排;而ResizeObserver会在元素尺寸真正变化时才触发回调,完全避免了窗口缩放带来的冗余触发。

内容的提问来源于stack exchange,提问作者임재혁

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 18:01:24