如何让useAuthentication返回状态控制useContext执行及优化方案
React认证钩子优化与路由布局条件执行方案
一、修复并改造useAuthentication钩子
你的useAuthenticated钩子存在两个核心问题:React钩子不能是异步函数,且未返回认证状态。我们通过状态管理来维护认证、加载、错误状态,改造后代码如下:
import { useState, useEffect } from 'react'; export const useAuthenticated = () => { // 管理认证状态:未认证/已认证 const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false); // 管理加载状态:避免API请求过程中误判状态 const [isLoading, setIsLoading] = useState<boolean>(true); // 可选:管理认证错误状态 const [authError, setAuthError] = useState<string | null>(null); useEffect(() => { const checkAuth = async () => { try { setIsLoading(true); // 调用API校验token const response = await fetch('/api/check-token', { headers: { Authorization: `Bearer ${localStorage.getItem('token')}` } }); setIsAuthenticated(response.ok); } catch (error) { setIsAuthenticated(false); setAuthError('认证请求失败'); console.error('认证校验出错:', error); } finally { setIsLoading(false); } }; checkAuth(); }, []); // 根据实际依赖调整,比如token变化时重新校验 return { isAuthenticated, isLoading, authError }; };
二、改造RouteLayout组件
注意:React钩子不能在条件语句中直接调用,因此不能写if (isAuth) useContext(...)。正确做法是:仅在认证通过时渲染依赖Context的内容,或把Context逻辑封装在子组件中通过条件渲染控制。
修改后的RouteLayout:
import { useContext } from 'react'; import { Outlet, useNavigate } from 'react-router-dom'; import { useAuthenticated } from './useAuthenticated'; import { YourCustomContext } from './YourCustomContext'; const RouteLayout: React.FC = () => { const { isAuthenticated, isLoading, authError } = useAuthenticated(); const navigate = useNavigate(); // 加载中状态:展示加载动画 if (isLoading) { return <div>正在校验身份...</div>; } // 认证失败:跳转登录页或展示错误 if (!isAuthenticated || authError) { navigate('/login'); return <div>请先登录</div>; } // 认证通过:安全使用Context const contextValue = useContext(YourCustomContext); return ( <div className="route-layout"> {/* 布局框架:导航栏、侧边栏等 */} <nav>全局导航</nav> {/* 渲染Context相关内容 */} {contextValue && <div>当前用户:{contextValue.user.name}</div>} {/* 子路由内容出口 */} <Outlet /> </div> ); }; export default RouteLayout;
三、更优实现建议
- 全局状态共享:若认证状态需在多组件共享,可将其存入全局状态(如Zustand、Redux或自定义Context),避免重复调用API校验token。
- 路由守卫封装:把认证逻辑封装成独立的
RequireAuth组件,直接包裹需要认证的路由,代码更简洁:
const RequireAuth: React.FC<{ children: React.ReactNode }> = ({ children }) => { const { isAuthenticated, isLoading } = useAuthenticated(); const navigate = useNavigate(); useEffect(() => { if (!isLoading && !isAuthenticated) navigate('/login'); }, [isAuthenticated, isLoading, navigate]); if (isLoading) return <div>加载中...</div>; if (!isAuthenticated) return null; return <>{children}</>; }; // 使用方式 <Route path="/dashboard" element={ <RequireAuth> <RouteLayout><Dashboard /></RouteLayout> </RequireAuth> } />
- 本地token预校验:校验前先通过JWT的
exp字段判断token是否过期,减少不必要的网络请求。 - 错误边界处理:给认证组件添加错误边界,捕获API请求失败等异常,提升用户体验。
内容的提问来源于stack exchange,提问作者Learn AspNet
相关产品推荐
相关产品推荐

