如何使用react hook在Next.js SSR中检测窗口大小?

问题描述

我正在使用Next.js和react-dates构建应用。

我有两个组件 DaterangePicker 组件和 DayPickerRangeController 组件。

我想在窗口的宽度大于1180px时呈现 DaterangePicker ,如果尺寸小于此值,我想呈现 DayPickerRangeController

代码如下:

      windowSize > 1180 ?
           <DaterangePicker
             startDatePlaceholderText="Start"
             startDate={startDate}
             startDateId="startDate"
             onDatesChange={handleOnDateChange}
             endDate={endDate}
             endDateId="endDate"
             focusedInput={focus}
             transitionDuration={0}
             onFocusChange={(focusedInput) => {
               if (!focusedInput) {
                 setFocus("startDate")
               } else {
                 setFocus(focusedInput)
                }
               }}
                /> :
             <DayPickerRangeController
               isOutsideRange={day => isInclusivelyBeforeDay(day,moment().add(-1,'days'))}
               startDate={startDate}
               onDatesChange={handleOnDateChange}
               endDate={endDate}
               focusedInput={focus}
               onFocusChange={(focusedInput) => {
               if (!focusedInput) {
                 setFocus("startDate")
                 } else {
                  setFocus(focusedInput)
                 }
               }}
              /> 
          }

我通常将带有窗口对象的react钩子用于检测窗口屏幕宽度,例如this

但是我发现在ssr时这种方法不可用,因为ssr渲染没有窗口对象

是否有其他方法可以安全地获得窗口大小而与ssr无关?

解决方法

您可以通过添加以下代码来避免在ssr中调用检测功能:

// make sure your function is being called in client side only
if (typeof window !== 'undefined') {
  // detect window screen width function
}

链接中的完整示例:

import { useState,useEffect } from 'react';

// Usage
function App() {
  const size = useWindowSize();

  return (
    <div>
      {size.width}px / {size.height}px
    </div>
  );
}

// Hook
function useWindowSize() {
  // Initialize state with undefined width/height so server and client renders match
  // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
  const [windowSize,setWindowSize] = useState({
    width: undefined,height: undefined,});

  useEffect(() => {
    // only execute all the code below in client side
    if (typeof window !== 'undefined') {
      // Handler to call on window resize
      function handleResize() {
        // Set window width/height to state
        setWindowSize({
          width: window.innerWidth,height: window.innerHeight,});
      }
    
      // Add event listener
      window.addEventListener("resize",handleResize);
     
      // Call handler right away so state gets updated with initial window size
      handleResize();
    
      // Remove event listener on cleanup
      return () => window.removeEventListener("resize",handleResize);
    }
  },[]); // Empty array ensures that effect is only run on mount
  return windowSize;
}
,

Darryl RN提供了绝对正确的答案。我想说一句:您实际上不需要检查window中是否存在useEffect对象,因为useEffect仅在客户端运行,而不在服务器端运行-端,window对象始终在客户端可用。