如何使用react钩子检测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 hook来检测窗口屏幕宽度,就像这个

但我发现这种方式在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
// 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;
}

注意:更新为Sergey Dubovik评论,我们不需要验证窗口,因为useEffect在客户端中运行

虽然Darryl RN提供了一个绝对正确的答案。我想说一句话:你真的不需要检查useEffect中是否存在window对象,因为useEffect只运行客户端,而从不运行服务器端,并且window对象在客户端上总是可用的。

useEffect(()=> {
window.addEventListener('resize', ()=> {
console.log(window.innerHeight, window.innerWidth)
})
}, [])

这是我正在使用的解决方案:在这里找到的一个小npm包使用窗口大小的

一旦安装并导入,您所需要做的就是这样使用它:

const { innerWidth, innerHeight, outerHeight, outerWidth } = useWindowSize();
return (
<div>Window width: {innerWidth}</div>
)

由于某种原因,我遇到了错误,但这对我来说很有效。仅限宽度:

const useWidth = () => {
const [width, setWidth] = useState(0)
const handleResize = () => setWidth(window.innerWidth)
useEffect(() => {
handleResize()
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return width
}

您可以对该页面使用"use client",并将其视为客户端组件,这就是

客户端组件

然后你可以避免所有的黑客,因为SSR否则。

相关内容

  • 没有找到相关文章

最新更新