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

React组件width props首次渲染传递后未定义,Footer响应式类名异常求助

React响应式宽度传递异常问题排查与修复

问题概况

我通过监听窗口宽度实现页面响应性,Header组件中获取宽度并逐层传递给Main、Footer子组件,但出现以下异常:

  • 首次渲染时控制台显示窗口宽度1879(110%缩放),但Footer却渲染了footer-vertical类(对应宽度≤1080的情况)
  • 首次放大窗口后,Main拿到正确宽度值,Footer拿到undefined
  • 重置窗口缩放时也会出现类似问题,其余场景功能正常

现有实现代码

Header组件的宽度监听

const [width, setwidth] = useState(window.innerWidth);
const handleResize = () => {
  setwidth(window.innerWidth);
};
useEffect(() => {
  window.addEventListener("resize", handleResize, false);
});

组件层级

  • Header
    • Main
      • Footer

子组件接收props方式

const [width, setwidth] = useState(props.width);
useEffect(() => {
  setwidth(props.width);
}, [props.width]);

Footer组件的类名判断

className={width > 1080 ? "footer" : "footer-vertical"}

问题根源与修复方案

1. 子组件无需维护独立state

你在子组件里把props转成自身state完全是冗余操作,这会导致props更新时state同步延迟,甚至出现值不一致的情况。直接使用props中的值即可,删掉子组件里的state和useEffect:

修改后Footer组件代码:

// 直接用props.width,无需自己的state
className={props.width > 1080 ? "footer" : "footer-vertical"}

2. Header组件的监听缺少清理逻辑

当前Header的useEffect没有移除resize事件监听,不仅会造成内存泄漏,还可能引发不必要的状态更新。同时,空依赖数组可以确保监听只绑定一次:

修改后Header组件代码:

const [width, setWidth] = useState(window.innerWidth);

const handleResize = () => {
  setWidth(window.innerWidth);
};

useEffect(() => {
  window.addEventListener("resize", handleResize, false);
  // 组件卸载时移除监听,避免内存泄漏
  return () => {
    window.removeEventListener("resize", handleResize, false);
  };
}, []); // 空依赖,仅初始化时执行一次

3. 检查props传递链路是否完整

确认Main组件是否正确将width传递给Footer,比如Main的JSX中是否写了:

<Footer width={props.width} />

如果Main组件自己维护了state但未将最新值传递给Footer,就会导致Footer拿到旧值或undefined。

4. 可选优化:用matchMedia替代resize监听

浏览器缩放时,window.innerWidth可能存在延迟,使用window.matchMedia监听断点会更精准:

Header组件优化代码:

// 直接监听断点,无需维护具体宽度值
const [isWideScreen, setIsWideScreen] = useState(window.matchMedia("(min-width: 1081px)").matches);

useEffect(() => {
  const mediaQuery = window.matchMedia("(min-width: 1081px)");
  const handleMediaChange = (e) => {
    setIsWideScreen(e.matches);
  };
  mediaQuery.addEventListener("change", handleMediaChange);
  return () => {
    mediaQuery.removeEventListener("change", handleMediaChange);
  };
}, []);

子组件直接使用isWideScreen:

className={isWideScreen ? "footer" : "footer-vertical"}

内容的提问来源于stack exchange,提问作者Grimalkin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 05:06:36