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,提问作者임재혁
相关产品推荐
相关产品推荐

