You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 11:17:59