React中如何随文档宽度变化修改组件状态?
如何在文档宽度变化时更新React组件状态?
嘿,这个需求在React开发里挺常见的,我来给你拆解清楚怎么实现~首先得纠正一个小误区:body元素并没有onChange事件(这个事件主要是给表单元素用的),如果要监听文档/视口的宽度变化,或者body自身的尺寸变化,我们需要用不同的方法,下面分两种场景给你具体方案:
场景1:监听浏览器视口宽度变化(最常见需求)
这是大部分“文档宽度变化”场景的核心需求,比如窗口缩放、设备横竖屏切换时的视口宽度变化。在React里,我们可以通过生命周期钩子(类组件)或者useEffect(函数组件)来绑定window的resize事件:
函数组件实现(React Hooks)
import { useState, useEffect } from 'react'; function WidthAwareComponent() { // 初始化状态为当前视口宽度 const [documentWidth, setDocumentWidth] = useState(window.innerWidth); // 定义尺寸变化的处理函数 const handleResize = () => { // 更新视口宽度 setDocumentWidth(window.innerWidth); // 如果需要获取body的实际宽度,可替换为: // setDocumentWidth(document.body.offsetWidth); }; useEffect(() => { // 组件挂载时绑定resize事件 window.addEventListener('resize', handleResize); // 组件卸载时移除事件监听,避免内存泄漏 return () => { window.removeEventListener('resize', handleResize); }; }, []); // 空依赖数组确保只在组件挂载时执行一次 return ( <div> 当前文档宽度:{documentWidth}px </div> ); } export default WidthAwareComponent;
类组件实现
import React from 'react'; class WidthAwareComponent extends React.Component { state = { documentWidth: window.innerWidth, }; handleResize = () => { this.setState({ documentWidth: window.innerWidth, // 如需body宽度可替换为:document.body.offsetWidth }); }; componentDidMount() { window.addEventListener('resize', this.handleResize); } componentWillUnmount() { window.removeEventListener('resize', this.handleResize); } render() { return ( <div> 当前文档宽度:{this.state.documentWidth}px </div> ); } } export default WidthAwareComponent;
场景2:监听body元素自身的尺寸变化(比如内容撑开body宽度)
如果你的需求是body元素自身的宽度变化(而非浏览器视口)——比如动态加载内容导致body宽度被撑开,这时候window.resize事件不会触发,我们需要用ResizeObserver API来监听body的尺寸变化:
函数组件示例
import { useState, useEffect, useRef } from 'react'; function BodyWidthAwareComponent() { const [bodyWidth, setBodyWidth] = useState(document.body.offsetWidth); // 用ref保存ResizeObserver实例,避免重复创建 const resizeObserverRef = useRef(null); useEffect(() => { // 初始化ResizeObserver resizeObserverRef.current = new ResizeObserver((entries) => { // 提取body元素的尺寸变化信息 const bodyEntry = entries[0]; setBodyWidth(bodyEntry.contentRect.width); }); // 开始监听body元素 const bodyElement = document.body; resizeObserverRef.current.observe(bodyElement); // 组件卸载时停止监听 return () => { if (resizeObserverRef.current) { resizeObserverRef.current.unobserve(bodyElement); resizeObserverRef.current.disconnect(); } }; }, []); return ( <div> 当前body宽度:{bodyWidth}px </div> ); } export default BodyWidthAwareComponent;
额外优化建议
- 防抖处理:
resize事件触发频率极高,建议给处理函数加防抖,避免频繁更新状态影响性能:// 简单的防抖函数 const debounce = (func, delay) => { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; }; // 使用防抖后的处理函数 const handleResize = debounce(() => { setDocumentWidth(window.innerWidth); }, 100); // 100ms延迟可根据需求调整 - 结合CSS媒体查询:如果只是做响应式UI展示,优先用CSS媒体查询实现;仅当需要在JS中做业务逻辑判断时,再使用上述监听方法。
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

