Next.js 12.2.5中HOC的getInitialProps跳转时不执行求助
问题原因与解决方案
核心问题
Next.js 12.2.5中,通过Link或按钮进行客户端路由跳转时,不会触发高阶组件的static getInitialProps——这个方法仅在页面首次加载(刷新、直接访问)时执行,客户端单页跳转时只会复用现有客户端状态,不会重新调用服务端/静态初始化方法。同时,客户端跳转时没有服务端上下文(context里的req/res),如果getCookie函数在客户端没有正确从document.cookie读取数据,就会丢失认证状态。
具体原因拆解
- getInitialProps的执行逻辑:Next.js的客户端路由(单页跳转)不会重新触发页面或高阶组件的
getInitialProps,只有首次加载/刷新时才会执行,不管是服务端渲染还是客户端首次渲染。 - 上下文丢失:客户端跳转时,
context参数为空(你设置了默认值false),如果getCookie函数在客户端没有正确处理document.cookie的读取,就拿不到FIREBASE_COOKIE的值。
解决方案
方案1:合并页面组件与高阶组件的getInitialProps
如果坚持用getInitialProps,需要确保页面组件的getInitialProps调用高阶组件的方法,同时处理客户端情况:
// AuthLayout.js static async getInitialProps(context) { try { const token = await getFirebaseCookie('id_token', context); return { isLoggedIn: !!token, token }; } catch (error) { console.log(error); return { isLoggedIn: false, token: null }; } } // 页面组件(比如pages/dashboard.js) Dashboard.getInitialProps = async (context) => { // 先调用AuthLayout的getInitialProps const authProps = await AuthLayout.getInitialProps(context); // 再添加页面自身的props(如果有的话) const pageProps = {}; return { ...authProps, ...pageProps }; }; export default AuthLayout(Dashboard);
方案2:改用客户端认证状态同步(适配客户端跳转)
在高阶组件中添加useEffect,在客户端渲染时重新读取cookie,确保跳转后状态更新:
import { useEffect, useState } from 'react'; const AuthLayout = ({ children, isLoggedIn: initialIsLoggedIn, token: initialToken }) => { const [isLoggedIn, setIsLoggedIn] = useState(initialIsLoggedIn); const [token, setToken] = useState(initialToken); useEffect(() => { // 客户端环境下重新读取cookie const fetchToken = async () => { const clientToken = await getFirebaseCookie('id_token'); setIsLoggedIn(!!clientToken); setToken(clientToken); }; fetchToken(); }, []); // 后续逻辑:根据isLoggedIn渲染内容 return <>{children}</>; }; // 保留原来的getInitialProps用于首次加载 AuthLayout.getInitialProps = async (context) => { try { const token = await getFirebaseCookie('id_token', context); return { isLoggedIn: !!token, token }; } catch (error) { console.log(error); return { isLoggedIn: false, token: null }; } }; export default AuthLayout;
方案3:改用getServerSideProps(推荐,更稳定)
放弃getInitialProps,在页面组件中使用getServerSideProps获取认证状态,再传递给高阶组件:
// pages/dashboard.js export async function getServerSideProps(context) { try { const token = await getFirebaseCookie('id_token', context); return { props: { isLoggedIn: !!token, token } }; } catch (error) { console.log(error); return { props: { isLoggedIn: false, token: null } }; } } export default AuthLayout(Dashboard);
关键补充:确保getCookie函数兼容客户端/服务端
检查getCookie函数的实现,确保客户端时从document.cookie读取,服务端时从context.req.headers.cookie读取:
const getCookie = (name, context) => { // 服务端环境 if (context && context.req) { const cookies = context.req.headers.cookie; if (!cookies) return null; const cookieArr = cookies.split(';'); for (let cookie of cookieArr) { const [key, value] = cookie.trim().split('='); if (key === name) { return JSON.parse(decodeURIComponent(value)); } } return null; } // 客户端环境 const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return JSON.parse(decodeURIComponent(parts.pop().split(';').shift())); return null; };
内容的提问来源于stack exchange,提问作者cb_dev
相关产品推荐
相关产品推荐

