Next.js SSR进入404页面后返回时出现属性未定义问题
问题分析与解决方案
你的问题不是导航组件导致的,核心原因是SSR页面拿到的服务端数据没有同步到客户端的useUser上下文里:
- 首次SSR加载时,
getServerSideProps返回的user会被用于服务端渲染页面,此时上下文可能已注入user,页面正常显示; - 从404页面通过
Link导航回SSR页面时,客户端会请求服务器执行getServerSideProps并返回userprops,但页面组件未将该props同步到useUser上下文,导致useUser()拿到的user为undefined,触发user!.id的属性未定义错误。
修复步骤
1. 修改SSR页面组件,同步服务端props到上下文
让MeSSR组件接收服务端返回的user props,并在客户端挂载时同步到上下文:
import { useUser } from "../context/user.context"; import { FC, useEffect } from 'react' import { GetServerSidePropsContext } from "next"; import { fetcherSSR } from "../lib/fether-ssr"; // 定义页面props类型,建议替换为实际的user类型 type MeSSRProps = { user: { id: string }; }; const MeSSR: FC<MeSSRProps> = ({ user }) => { const { setUser } = useUser(); // 客户端挂载时同步服务端返回的user到上下文 useEffect(() => { if (user) { setUser(user); } }, [user, setUser]); // 增加加载判断,避免客户端hydrate阶段的错误 if (!user) { return <div>Loading...</div>; } return ( <main className="flex items-center justify-center h-full"> <div className="text-center space-y-4"> <h1 className="px-4 py-2 text-lg font-medium bg-gray-200 rounded"> Server side authentication </h1> <p>Hi, {user.id} 👋</p> </div> </main> ) } export default MeSSR export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { const {req, res} = ctx; const [error, user] = await fetcherSSR(req, res, 'http://localhost:3000/user/profile') if(!user) return {redirect: {statusCode:307, destination: '/login'}} return {props:{user}} }
2. 优化UserContext支持服务端初始化(可选)
如果你的user.context是基础的createContext实现,建议在_app.tsx中通过页面props传递初始user,确保服务端渲染和客户端hydrate的数据一致:
// _app.tsx import { UserProvider } from "../context/user.context"; import type { AppProps } from 'next/app' function MyApp({ Component, pageProps }: AppProps) { return ( <UserProvider initialUser={pageProps.user}> <Component {...pageProps} /> </UserProvider> ) } export default MyApp
修改user.context.ts,支持初始值注入:
import { createContext, useContext, useState } from 'react'; type User = { id: string; // 补充其他user属性 }; type UserContextType = { user: User | null; setUser: (user: User | null) => void; }; const UserContext = createContext<UserContextType | undefined>(undefined); export function UserProvider({ children, initialUser }: { children: React.ReactNode; initialUser?: User }) { const [user, setUser] = useState<User | null>(initialUser || null); return ( <UserContext.Provider value={{ user, setUser }}> {children} </UserContext.Provider> ); } export function useUser() { const context = useContext(UserContext); if (context === undefined) { throw new Error('useUser must be used within a UserProvider'); } return context; }
为什么导航组件没问题?
你的导航组件使用next/link的逻辑是正确的:Link触发客户端导航时,Next.js会自动向服务器请求执行getServerSideProps并获取页面数据,导航本身不存在问题。
内容的提问来源于stack exchange,提问作者Firdaus Ismail
相关产品推荐
相关产品推荐

