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

Next.js中在useEffect内设置window.innerWidth及自定义useWindowSize钩子初始值配置问题

在Next.js中修复useWindowSize钩子的初始值问题

我明白你遇到的问题了——在Next.js这类SSR框架里,自定义的useWindowSize钩子初始值为null,只有窗口 resize 后才更新,这是因为服务端渲染阶段根本没有window对象,导致初始状态没正确设置。下面我给你两种可靠的解决办法,帮你搞定初始值的问题:

方法一:在useState初始化时区分服务端/客户端

直接在useState的函数式初始化中判断环境,客户端直接获取当前窗口尺寸,服务端返回一个合理的默认值(比如0或者你预期的初始宽度):

import { useState, useEffect } from 'react';

export function useWindowSize() {
  // 函数式初始化只会执行一次,避免重复判断window
  const [windowSize, setWindowSize] = useState(() => {
    if (typeof window !== 'undefined') {
      // 客户端环境:直接获取当前窗口宽高
      return {
        width: window.innerWidth,
        height: window.innerHeight,
      };
    }
    // 服务端环境:返回默认值,可根据需求调整(比如移动端默认宽度375)
    return { width: 0, height: 0 };
  });

  useEffect(() => {
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    // 监听窗口 resize 事件
    window.addEventListener('resize', handleResize);

    // 清理事件监听
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;
}

使用这个钩子时,初始值就会是客户端当前的窗口尺寸(服务端渲染时是默认值),不会再出现null的情况。

方法二:解决Hydration不匹配警告(可选)

如果服务端的默认值和客户端实际窗口尺寸差异较大,Next.js可能会抛出Hydration不匹配的警告。这时候可以在客户端挂载完成后,强制更新一次窗口尺寸:

import { useState, useEffect } from 'react';

export function useWindowSize() {
  const [windowSize, setWindowSize] = useState({ width: 0, height: 0 });

  useEffect(() => {
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    // 客户端挂载后立即更新一次,确保和实际窗口一致
    handleResize();

    // 监听 resize 事件
    window.addEventListener('resize', handleResize);

    return () => window.removeEventListener('resize', handleResize);
  }, []);

  // 服务端渲染时可以返回null或者默认值,客户端会很快更新
  return typeof window !== 'undefined' ? windowSize : { width: 0, height: 0 };
}

这样既保证了服务端渲染时不会报错,客户端挂载后也能立刻拿到正确的初始值。

小提醒

你原来的代码里console.log(``, useWindowSize);是打印钩子函数本身,而不是它返回的状态值,应该改成console.log(windowSize);才能看到正确的窗口尺寸数据哦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 15:27:31