React中用useEffect监听window.innerWidth重渲染页面及代码问题排查
代码存在的问题
- 依赖项不具备响应性:
window.innerWidth是浏览器提供的原生属性,不属于React的响应式状态,放在useEffect的依赖数组中无法被React感知变更,因此这段useEffect只会在组件首次挂载时执行一次,后续窗口宽度变化完全不会触发回调,达不到实时监听的效果。 - 边界条件遗漏:两个判断分支仅覆盖了窗口宽度小于800px、大于800px的场景,当宽度刚好等于800px时没有任何逻辑触发,body的display属性会保留上一次的设置值,可能出现不符合预期的展示结果。
- 直接操作全局DOM不符合开发规范:直接修改body的样式属于全局操作,既不符合React状态驱动UI的设计理念,也容易和其他修改body样式的逻辑产生冲突,后续排查问题成本较高。
修复方案
如果你需要用JS实现尺寸监听,首先需要绑定窗口的resize事件来同步更新响应式状态,示例代码如下:
import { useState, useEffect } from 'react'; function YourComponent() { // 定义响应式的窗口宽度状态 const [windowWidth, setWindowWidth] = useState(window.innerWidth); useEffect(() => { const handleResize = () => { setWindowWidth(window.innerWidth); }; // 监听窗口resize事件 window.addEventListener('resize', handleResize); // 组件卸载时移除事件监听,避免内存泄漏 return () => window.removeEventListener('resize', handleResize); }, []); useEffect(() => { console.log("am called"); if (windowWidth < 800) { document.body.style.display = "none"; } else { // 覆盖等于、大于800px的所有场景 document.body.style.display = "block"; } }, [windowWidth]); // 组件其他逻辑 return <></>; }
提示:如果对性能要求较高,可以给handleResize函数加上节流处理,避免窗口拖动过程中频繁触发状态更新
如果只是需要实现小于800px时隐藏页面的效果,更推荐直接使用CSS媒体查询实现,性能远高于JS监听:
@media (max-width: 799px) { body { display: none; } }
内容的提问来源于stack exchange,提问作者tedGuy
相关产品推荐
相关产品推荐

