页面加载及窗口resize时按屏幕尺寸更新状态异常问题
问题分析与修复方案
核心问题
load事件绑定时机滞后:组件渲染时才绑定load事件,但此时页面大概率已加载完成,导致该事件不会触发,页面初始化时mobile状态未同步实际窗口尺寸。- 缺少初始状态同步:组件挂载后未立即检查窗口宽度,导致初始显示的导航样式和当前窗口尺寸不匹配。
- 未清理事件监听:组件卸载时未移除
resize监听,会引发内存泄漏,还可能导致重复触发状态更新。
修复代码
使用React的useEffect钩子处理事件监听与初始状态同步,这是React中处理此类副作用的标准方式:
import { useState, useEffect } from 'react'; // ... const [mobile, setMobile] = useState(false); const handleResize = () => { setMobile(window.innerWidth <= 468); }; useEffect(() => { // 组件挂载时立即执行,同步初始窗口状态 handleResize(); // 绑定resize事件监听 window.addEventListener('resize', handleResize); // 组件卸载时清理监听,避免内存泄漏 return () => { window.removeEventListener('resize', handleResize); }; }, []); // 空依赖数组确保仅在挂载/卸载阶段执行 return ( <nav className={ navColor ? css.nav__container : `${css.nav__container} ${css.nav__blur}` }> <a href='#' onClick={() => setActiveNav('#')} className={activeNav === '#' ? css.nav__active : ''}> {mobile ? <RiHome3Line /> : 'Home'} </a> </nav> );
可选优化:防抖处理
如果resize事件触发过于频繁,可添加防抖逻辑减少状态更新次数:
import { useState, useEffect, useCallback } from 'react'; // 若未引入防抖工具,可自行实现或使用lodash.debounce const debounce = (func, delay) => { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; }; // ... const [mobile, setMobile] = useState(false); const handleResize = useCallback(() => { setMobile(window.innerWidth <= 468); }, []); const debouncedResize = useCallback(debounce(handleResize, 100), [handleResize]); useEffect(() => { handleResize(); window.addEventListener('resize', debouncedResize); return () => { window.removeEventListener('resize', debouncedResize); }; }, [debouncedResize, handleResize]);
原写法失效原因
- 组件顶层直接绑定事件监听,会在每次组件渲染时重复绑定,导致多次触发状态更新;且组件卸载后监听仍存在,引发内存泄漏。
load事件在组件渲染时可能已触发完毕,绑定后无法再触发,导致初始状态错误。
内容的提问来源于stack exchange,提问作者Majeev
相关产品推荐
相关产品推荐

