如何在react-router-dom 6.4中将解码后的Google JWT对象传入Layout组件
解决方案
1. 完善 useToken.js 自定义Hook,管理Token与用户信息
先确保useToken Hook不仅存储token,还能自动解码并维护userObject状态,让应用各部分能便捷获取用户信息:
import { useState, useEffect } from 'react'; import jwt_decode from 'jwt-decode'; export default function useToken() { // 从localStorage初始化token const getToken = () => { const tokenString = localStorage.getItem('token'); const userToken = JSON.parse(tokenString); return userToken?.token; }; // 解码token得到用户信息 const getCurrentUser = () => { const token = getToken(); if (token) { try { return jwt_decode(token); } catch (err) { console.error('Token解码失败:', err); return null; } } return null; }; const [token, setToken] = useState(getToken()); const [user, setUser] = useState(getCurrentUser()); // token变化时自动更新用户信息 useEffect(() => { setUser(getCurrentUser()); }, [token]); const saveToken = (userToken) => { localStorage.setItem('token', JSON.stringify(userToken)); setToken(userToken.token); }; const removeToken = () => { localStorage.removeItem('token'); setToken(null); setUser(null); }; return { setToken: saveToken, removeToken, token, user }; }
2. 在 App.js 中配置路由,传递用户信息到Layout
react-router-dom 6.4采用createBrowserRouter+RouterProvider配置路由,将Layout作为父路由的element,直接把user作为props传入,让所有子路由都被Layout包裹并能访问用户信息:
import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import useToken from './useToken'; import Layout from './Layout'; import Login from './Login'; import Dashboard from './Dashboard'; // 示例子页面 function App() { const { user } = useToken(); const router = createBrowserRouter([ { path: '/', element: <Layout user={user} />, // 传递用户信息到Layout children: [ { path: 'dashboard', element: <Dashboard />, }, // 其他子路由... ], }, { path: '/login', element: <Login />, }, ]); return <RouterProvider router={router} />; } export default App;
3. 修改 Layout.js 接收并展示用户名称
在Layout组件中接收user props,在头部区域渲染用户名:
import { Outlet, Link } from 'react-router-dom'; export default function Layout({ user }) { return ( <div className="app-container"> <header className="header"> <nav> <Link to="/dashboard">首页</Link> {user ? ( <span className="user-name">欢迎, {user.name}</span> ) : ( <Link to="/login">登录</Link> )} </nav> </header> <main> <Outlet /> {/* 渲染子路由内容 */} </main> </div> ); }
4. 更新 Login.js,登录成功后存储Token
Google登录成功后,调用useToken的setToken方法存储token,触发user状态更新并跳转页面:
import { useNavigate } from 'react-router-dom'; import useToken from './useToken'; export default function Login() { const navigate = useNavigate(); const { setToken } = useToken(); const handleGoogleLoginSuccess = (response) => { // 假设response.id_token是Google返回的JWT const token = response.id_token; setToken({ token }); // 存储token navigate('/dashboard'); // 跳转到首页 }; return ( <div className="login-container"> {/* Google登录按钮,绑定登录成功回调 */} <button onClick={handleGoogleLoginSuccess}>Google登录</button> </div> ); }
额外优化:用Context全局共享用户信息(可选)
如果应用多个组件都需要访问用户信息,推荐用React Context全局共享,避免逐层传props:
创建 UserContext.js
import { createContext, useContext } from 'react'; import useToken from './useToken'; const UserContext = createContext(); export function UserProvider({ children }) { const { user, token, setToken, removeToken } = useToken(); return ( <UserContext.Provider value={{ user, token, setToken, removeToken }}> {children} </UserContext.Provider> ); } export function useUser() { return useContext(UserContext); }
修改 App.js 包裹UserProvider
import { UserProvider } from './UserContext'; function App() { return ( <UserProvider> <RouterProvider router={router} /> </UserProvider> ); }
修改 Layout.js 使用useUser Hook
import { useUser } from './UserContext'; export default function Layout() { const { user } = useUser(); // 后续渲染逻辑不变 }
内容的提问来源于stack exchange,提问作者Europa
相关产品推荐
相关产品推荐

