如何在Next.js的getInitialProps/getServerSideProps中获取Auth0用户数据?
问题(中文翻译)
我想通过仅能在页面函数组件中调用的Auth0 useUser Hook加载数据,但这个Hook是异步操作,导致渲染<Home user={data}>时数据还没准备好,Home组件会先于数据加载完成就渲染。我尝试在getInitialProps里调用getUser Hook,但Next.js不允许这么做;使用@auth0/nextjs-auth0的getSession方法时,有时候会出现user.user为undefined的情况。请问有没有更好的方案能让Hook数据在页面渲染时就可用?
代码示例:
import getUser from './api/hooks/user'; import Homepage from './home'; function Controller ({userAuth}) { //2. 只能在这里调用 //let user = getUser(); return <Homepage user={userAuth} /> } Controller.getInitialProps = async (context) => { //1. 这么写不行,Next.js禁止 let user = getUser(); //3. 但getInitialProps、getStaticProps、getServerSideProps会把数据作为props传给页面组件,且仅在数据就绪后渲染页面 return{userAuth: user} } export default Controller;
//4. 我也试过这种写法 import { getSession } from '@auth0/nextjs-auth0'; Controller.getInitialProps = async (context) => { //5. getUser Hook返回的user对象本该在这里 let user = getSession(); //6. 但有时候user.user会返回undefined return{userAuth: user.user} }
解决方案
方案1:修复getSession调用方式,稳定获取用户数据
你之前出现user.user undefined的问题,大概率是没给getSession传入请求上下文。getSession需要接收req和res参数才能正确读取服务器端会话,同时要处理会话不存在的边界情况。
修改后的代码:
import { getSession } from '@auth0/nextjs-auth0'; import Homepage from './home'; function Controller({ userAuth }) { return <Homepage user={userAuth} />; } Controller.getInitialProps = async (context) => { // 必须传入req和res上下文 const session = await getSession(context.req, context.res); // 处理会话不存在的情况,避免undefined报错 const userAuth = session?.user || null; return { userAuth }; }; export default Controller;
如果用户未登录,userAuth会是null,你可以在Home组件里添加未登录状态的处理逻辑,比如跳转登录页。
方案2:使用withPageAuthRequired高阶组件(推荐)
@auth0/nextjs-auth0提供的withPageAuthRequired高阶组件,会自动在页面渲染前完成会话校验和用户数据获取,无需手动处理getSession,还能自动跳转登录页(如果用户未登录)。
代码示例:
import { withPageAuthRequired, getSession } from '@auth0/nextjs-auth0'; import Homepage from './home'; function Controller({ userAuth }) { return <Homepage user={userAuth} />; } // 用高阶组件包裹页面组件 export default withPageAuthRequired(Controller, { // 可选:自定义登录成功后的跳转路径 returnTo: '/', // 获取用户数据并传递给页面组件 async getServerSideProps(context) { const session = await getSession(context.req, context.res); return { props: { userAuth: session?.user } }; }, });
这个方案最省心,既保证页面渲染时用户数据已就绪,又处理了未登录的跳转逻辑。
方案3:组件内处理加载状态(兜底方案)
如果因为某些限制不能用SSR,只能在组件内使用useUser Hook,那可以在Controller组件里添加加载状态,等用户数据就绪后再渲染Home组件:
import { useUser } from '@auth0/nextjs-auth0'; import Homepage from './home'; export default function Controller() { const { user, isLoading, error } = useUser(); // 加载中显示占位符 if (isLoading) return <div>加载中...</div>; // 出错时提示 if (error) return <div>加载用户数据失败</div>; // 未登录时处理 if (!user) return <div>请先登录</div>; // 数据就绪后渲染Home组件 return <Homepage user={user} />; }
这个方案虽然不能让页面直接渲染带用户数据的Home,但能避免Home组件接收undefined的情况,提升用户体验。
内容的提问来源于stack exchange,提问作者investrill prototype

