Next.js 13中如何通过router.push传递状态或Props?
在Next.js 13的App Router体系下,next/navigation提供的useRouter和旧版next/router的用法存在差异,无法直接通过push方法附加自定义状态数据。针对你的登录场景,以下是几种可行的解决方案:
方案1:URL查询参数传递(仅适用于非敏感数据)
如果要传递的是无需保密的数据,可以将数据拼接为URL查询参数:
// 登录组件中修改跳转逻辑 router.push(`/dashboard?email=${encodeURIComponent(user.email)}`);
之后在/dashboard客户端组件中,用useSearchParams获取参数:
'use client'; import { useSearchParams } from 'next/navigation'; export default function Dashboard() { const searchParams = useSearchParams(); const email = searchParams.get('email'); return <div>当前登录邮箱:{email}</div>; }
⚠️ 注意:绝对不要用这种方式传递密码等敏感数据,会直接暴露在URL中,存在安全风险。
方案2:直接从Supabase获取用户数据(推荐方案)
你的代码已经通过Supabase完成登录,Supabase会自动维护用户会话状态,完全没必要通过路由传递用户数据。直接在/dashboard页面中获取当前登录用户即可:
Dashboard页面代码示例:
'use client'; import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'; import { useEffect, useState } from 'react'; export default function Dashboard() { const [currentUser, setCurrentUser] = useState(null); const supabase = createBrowserSupabaseClient(); useEffect(() => { // 初始化获取用户 const getCurrentUser = async () => { const { data: { user } } = await supabase.auth.getUser(); setCurrentUser(user); }; getCurrentUser(); // 监听用户会话变化,实时更新状态 const { data: listener } = supabase.auth.onAuthStateChange((_event, session) => { setCurrentUser(session?.user ?? null); }); return () => listener.unsubscribe(); }, [supabase]); if (!currentUser) return <div>加载中...</div>; return ( <div> <h1>欢迎回来,{currentUser.email}</h1> </div> ); }
这种方式既安全又符合Supabase的最佳实践,不需要额外做数据传递的工作。
方案3:客户端状态管理(跨组件共享数据)
如果需要在多个组件间共享用户状态,可以使用React Context或状态管理工具(如Zustand):
- 创建用户Context:
// app/context/UserContext.tsx 'use client'; import { createContext, useContext, useState, useEffect, ReactNode } from 'react'; import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'; type UserContextType = { user: any | null; }; const UserContext = createContext<UserContextType | undefined>(undefined); export function UserProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null); const supabase = createBrowserSupabaseClient(); useEffect(() => { const fetchUser = async () => { const { data: { user } } = await supabase.auth.getUser(); setUser(user); }; fetchUser(); const { data: listener } = supabase.auth.onAuthStateChange((_event, session) => { setUser(session?.user ?? null); }); return () => listener.unsubscribe(); }, [supabase]); return ( <UserContext.Provider value={{ user }}> {children} </UserContext.Provider> ); } export function useUser() { const context = useContext(UserContext); if (context === undefined) { throw new Error('useUser必须在UserProvider内部使用'); } return context; }
- 在根布局中包裹Provider:
// app/layout.tsx import { UserProvider } from './context/UserContext'; export default function RootLayout({ children }: { children: ReactNode }) { return ( <html lang="zh-CN"> <body> <UserProvider>{children}</UserProvider> </body> </html> ); }
- 登录组件和Dashboard组件直接使用状态:
登录组件只需完成登录后跳转即可:
// 登录组件中修改登录逻辑 const login = async (e: FormEvent) => { e.preventDefault(); const { data, error } = await supabase.auth.signInWithPassword({ email: user.email, password: user.password, }); if (!error) { router.push('/dashboard'); } else { // 处理登录错误 console.error(error.message); } }
Dashboard组件直接获取用户状态:
// Dashboard组件 'use client'; import { useUser } from '../context/UserContext'; export default function Dashboard() { const { user } = useUser(); if (!user) return <div>加载中...</div>; return <h1>欢迎,{user.email}</h1>; }
另外,你的登录组件中有一段无实际作用的useEffect,可以直接删除:
// 这段代码没有任何功能,还会触发不必要的重渲染,建议删除 useEffect(() => { setUser({ email: user.email, password: user.password }); }, []);
内容的提问来源于stack exchange,提问作者Yustina Yasin
相关产品推荐
相关产品推荐

