我正在使用Next.js 13与应用路由器,并有以下客户端组件,它使用JavaScript中的媒体查询来显示小/大屏幕的侧边栏。
"use client";
export default function Feed() {
const [isLargeScreen, setIsLargeScreen] = useState(window.matchMedia("(min-width: 768px)").matches);
useEffect(() => {
window
.matchMedia("(min-width: 1024px)")
.addEventListener('change', e => setIsLargeScreen(e.matches));
}, []);
return (
<div>
<Sidebar isLargeScreen={isLargeScreen}/>
<div>...</div>
</div>
)
}
字符串
现在,网站在客户端内完美加载,但由于Next.js应用路由器在服务器上呈现此组件一次,并且服务器没有window
属性,因此我将始终在服务器上获得此错误(在本地开发模式下运行npm run dev
的控制台):
error ReferenceError: window is not defined
at Feed (./app/feed/page.tsx:32:95)
> 17 | const [isLargeScreen, setIsLargeScreen] = useState(window.matchMedia("(min-width: 768px)").matches);
型
我可以用如下的if-else替换这条麻烦的代码行:
const [isLargeScreen, setIsLargeScreen] = useState(typeof window == "undefined" ? true : window.matchMedia("(min-width: 768px)").matches);
型
如果服务器呈现状态设置为true
的组件,而客户端(在本例中在小屏幕上)呈现状态设置为false
的组件,则会导致客户端上的运行时错误:
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
型
如何更改此组件,使服务器和客户端不会抛出任何错误?
2条答案
按热度按时间idv4meu81#
我认为你可以在Next.js中使用类似“懒惰补水”的技巧,有几种方法,例如:
您可以通过创建一个新文件(useIsLargeScreen?)在hooks文件夹中:
字符串
然后在Feed组件上使用此钩子:
型
另一种方法是动态导入你的侧边栏,像这样:
型
还有第三种通用方法来修复水合误差:
型
63lcw9qa2#
我已经看到,有时候在客户端组件中获取窗口对象需要时间,而且通常需要进行递归检查。
字符串