我有一个
<Authenticated>
组件,用于渲染所有经过身份验证的路由。我想阻止渲染页面,直到检查了存储在 sessionStorage
中的令牌。
'use client';
export const Authenticated = ({ children }) => {
const token = typeof window !== 'undefined' ? sessionStorage.getItem('token') : null;
if (!token) {
return <></>;
}
return (
<main>{children}</main>
);
}
这有效,但我收到此水合作用错误:
Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
有更好的方法吗?
根据 Next.js 文档 水合错误可能由以下原因引起:
在渲染逻辑中使用
之类的检查typeof window !== 'undefined'
这就是你在这里所做的:
const token = typeof window !== 'undefined' ? sessionStorage.getItem('token') : null;
而是将会话处理逻辑包装到
useEffect
钩子中。这将确保您仅在页面完全加载并且 token
可用时检查 window
:
'use client';
import React, {useState, useEffect} from 'react';
export const Authenticated = ({ children }) => {
const [token, setToken] = useState('');
useEffect(() => {
setToken(window.sessionStorage.getItem('token'))
}, [])
return (
{token ? <main>children</main> : null}
);
}
此方法需要注意的一些事项:
我们使用state来存储令牌。这是因为在
token
运行之前 useEffect
将为假。这让我们可以在检索到令牌后更新状态并重新渲染 UI
基于最后一点,我们使用三元运算符来确定是否渲染某些内容。以前的方法可能不起作用的原因(即使您修复了水合错误)是因为这个逻辑错误,您的代码说:
{children}
问题是第一个条件永远是
true
,然后可能是假的。不过,目前你只能在满足真实条件之前返回。但是当在单个 return
上使用 if/else 逻辑时,你可以解决这个问题