在 Next.js 中创建自定义 React hook 来获取窗口尺寸 经典实现 SSR 地狱 解决方案

2025-06-04

在 Next.js 中创建自定义 React hook 来获取窗口尺寸

经典实现

SSR地狱

解决方案

在使用 React App 的前端时,您可能需要在某个时候访问窗口的尺寸。

经典实现

为了保持代码 DRY 原则,一个普遍的良好做法是将此操作外部化到自定义的 React hook 中。
例如:



// useWindowDimension.js
const [width, setWidth]   = useState(window.innerWidth);
const [height, setHeight] = useState(window.innerHeight);
const updateDimensions = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
}
useEffect(() => {
    window.addEventListener("resize", updateDimensions);
    return () => window.removeEventListener("resize", updateDimensions);
}, []);

return { width, height};


Enter fullscreen mode Exit fullscreen mode

虽然在使用 React(如 create-react-app)构建的传统客户端应用程序中一切运行良好,但 Gatsby 或 Next.js 中出现了问题。

SSR地狱

Next 和 Gatsby 的主要问题是它们在 FE 和 BE 上都运行代码……window显然没有定义 where 在哪里。
那么,我听到有人问,该如何解决这个问题呢?

好吧,您可以写类似这样的内容,在继续之前检查窗口是否已定义。



// useWindowDimension.js
import { useState, useEffect } from 'react';

export default function useWindowDimensions() {

  const hasWindow = typeof window !== 'undefined';

  function getWindowDimensions() {
    const width = hasWindow ? window.innerWidth : null;
    const height = hasWindow ? window.innerHeight : null;
    return {
      width,
      height,
    };
  }

  const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

  useEffect(() => {
    if (hasWindow) {
      function handleResize() {
        setWindowDimensions(getWindowDimensions());
      }

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

  return windowDimensions;
}


Enter fullscreen mode Exit fullscreen mode

请注意,在撰写本文时,这是Stackoverflow上关于 Next.js 实现的投票最高的答案
但是,尝试此代码会在 Next.js 中触发警告:
警告下一个

那么,为什么这个代码有缺陷,我们如何才能使它万无一失?

解决方案

直到读了Josh 的《W Comeau》之后,我才意识到问题所在。上面的实现实际上是通过检查窗口对象是否定义来绕过 Rehydration 过程的
! 更好的实现应该是确保组件已经挂载(并使用useEffect钩子)。

最终的自定义钩子看起来像这样,每个人都很高兴!



/**
 * // useWindowDimension.ts
 * * This hook returns the viewport/window height and width
 */

import { useEffect, useState } from 'react';

type WindowDimentions = {
    width: number | undefined;
    height: number | undefined;
};

const useWindowDimensions = (): WindowDimentions => {
    const [windowDimensions, setWindowDimensions] = useState<WindowDimentions>({
        width: undefined,
        height: undefined,
    });
    useEffect(() => {
        function handleResize(): void {
            setWindowDimensions({
                width: window.innerWidth,
                height: window.innerHeight,
            });
        }
        handleResize();
        window.addEventListener('resize', handleResize);
        return (): void => window.removeEventListener('resize', handleResize);
    }, []); // Empty array ensures that effect is only run on mount

    return windowDimensions;
};

export default useWindowDimensions;


Enter fullscreen mode Exit fullscreen mode

用法:



import { useWindowDimensions } from '@hooks/useWindowDimensions';
...
const { width, height } = useWindowDimensions();


Enter fullscreen mode Exit fullscreen mode
文章来源:https://dev.to/adrien/creating-a-custom-react-hook-to-get-the-window-s-dimensions-in-next-js-135k
PREV
CSS 艺术入门
NEXT
Github 个人资料自述文件 GitHub 个人资料自述文件生成器