NextJS中组件如何在页面加载时正确获取显示窗口宽度
报错原因
这个错误基本都出在服务端渲染(SSR)场景:SSR阶段代码运行在Node服务端环境,不存在浏览器专属的window对象,你在useState初始化时直接调用window.innerWidth,服务端执行到这行就会直接抛出ReferenceError: window is not defined。
你之前把初始值写死为0的版本能运行但初始值不准,是因为useEffect只会在组件挂载到客户端浏览器后才执行,首屏渲染阶段用的是初始值0,会出现首屏显示宽度错误,甚至触发React hydration不匹配的警告。
修复方案
核心逻辑分两点:
- 初始化状态时先判断当前运行环境,只有客户端存在
window对象时才读取window.innerWidth,服务端阶段用默认值兜底,从根源避免访问不存在的对象报错 - 在组件首次挂载的
useEffect回调里,第一时间同步一次真实窗口宽度,修正兜底默认值带来的首屏数值不准问题,之后再绑定resize事件监听实现宽度动态更新
修正后的完整代码如下:
import React, { useState, useEffect } from "react"; const WindowTracker = () => { const [show, setShow] = useState(true); // 用函数式初始化做环境判断,逻辑仅在状态初始化时执行一次,性能更好 const [windowWidth, setWindowWidth] = useState(() => { return typeof window !== "undefined" ? window.innerWidth : 0; }); const triggerToggle = () => { setShow(!show); }; useEffect(() => { // 组件挂载到客户端后立刻更新真实宽度,兜底初始化默认值 setWindowWidth(window.innerWidth); function watchWidth() { setWindowWidth(window.innerWidth); } window.addEventListener("resize", watchWidth); // 组件卸载时移除监听,避免内存泄漏 return () => { window.removeEventListener("resize", watchWidth); }; }, []); return ( <div> <button onClick={triggerToggle}>Toggle WindowTracker</button> {show && <h1>Window width: {windowWidth}px</h1>} </div> ); }; export default WindowTracker;
如果你用的是Next.js 13+ App Router这类强制区分服务端/客户端组件的框架,只需要在文件最顶部加一行'use client'声明这是客户端组件,配合上面的环境判断逻辑,就不会再出现window未定义或者初始值不准的问题。
内容的提问来源于stack exchange,提问作者Lil Robots
相关产品推荐
相关产品推荐

