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

如何在TanStack Router中实现类似React的上下文管理?

在TanStack Router中实现Auth上下文管理

以下是基于你现有React AuthContext代码,在TanStack Router中实现认证状态管理的两种方案,兼顾兼容性和TanStack Router的特性:


方案一:保留原有React Context,集成到TanStack Router

TanStack Router完全兼容React Context,你可以保留现有代码,只需要调整集成方式,同时利用TanStack Router的路由保护能力。

1. 保留原有Auth代码

你的AuthContext.tsx和AuthContextProvider.tsx无需修改,继续作为状态管理的核心。

2. 将AuthProvider包裹在Router外层

在路由入口文件(如main.tsx或App.tsx)中,把Auth上下文提供者包裹在TanStack Router外面:

import { RouterProvider, createRouter } from '@tanstack/react-router';
import AuthContextProvider from './AuthContextProvider';
import { routes } from './routes';

const router = createRouter({ routes });

function App() {
  return (
    <AuthContextProvider>
      <RouterProvider router={router} />
    </AuthContextProvider>
  );
}

export default App;

3. 在路由组件中使用Auth状态

和之前一样,在任何路由组件里用useAuthContext()获取认证信息:

import { useAuthContext } from './AuthContext';

function ProfilePage() {
  const { user, isAuthenticated } = useAuthContext();
  
  if (!isAuthenticated) {
    return <div>请先登录</div>;
  }

  return <div>欢迎回来,{user?.name}</div>;
}

4. 实现路由级认证保护

TanStack Router的beforeLoad钩子可以在路由加载前拦截未认证请求,要让钩子能访问Auth状态,需要把Auth状态同步到Router Context:

修改AuthContextProvider同步状态到Router Context

import {ReactNode, useEffect, useState} from 'react';
import {AuthContext} from './AuthContext';
import {Token, User} from '@/types';
import {QUERY_KEYS} from '@/lib/react-query/queryKeys';
import {jwtDecode} from 'jwt-decode';
import { useRouter } from '@tanstack/react-router';

const AuthContextProvider = ({children}: {children: ReactNode}) => {
  const [user, setUser] = useState<User | null>(null);
  const [token, setToken] = useState<Token | null>(null);
  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
  const router = useRouter();

  useEffect(() => {
    const storedToken = JSON.parse(localStorage.getItem(QUERY_KEYS.TOKEN) || 'null');

    if (storedToken) {
      const decodedToken = jwtDecode(storedToken.accessToken) as User;

      if (decodedToken.exp && decodedToken.exp * 1000 < Date.now()) {
        localStorage.removeItem(QUERY_KEYS.TOKEN);
        setToken(null);
        setUser(null);
        setIsAuthenticated(false);
      } else {
        setToken(storedToken);
        setUser(decodedToken);
        setIsAuthenticated(true);
      }
    }
  }, []);

  // 同步Auth状态到Router Context,让loader/beforeLoad能访问
  useEffect(() => {
    router.setContext(old => ({
      ...old,
      auth: { user, token, isAuthenticated, setUser, setToken, setIsAuthenticated }
    }));
  }, [user, token, isAuthenticated, setUser, setToken, setIsAuthenticated, router]);

  const contextValue = {
    user,
    setUser,
    token,
    setToken,
    isAuthenticated,
    setIsAuthenticated,
  };

  return (
    <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>
  );
};

export default AuthContextProvider;

初始化Router Context

const router = createRouter({
  routes,
  context: {
    auth: {
      user: null,
      token: null,
      isAuthenticated: false,
      setUser: () => {},
      setToken: () => {},
      setIsAuthenticated: () => {},
    },
  },
});

在路由中添加保护

import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/profile')({
  beforeLoad: async ({ redirect, context }) => {
    if (!context.auth.isAuthenticated) {
      await redirect({ to: '/login' });
    }
  },
  component: ProfilePage,
});

方案二:完全基于TanStack Router Context实现

如果不想依赖React Context,可以直接用TanStack Router自带的Context管理认证状态:

1. 编写Auth状态工具函数

创建auth.ts:

import { Token, User } from '@/types';
import { QUERY_KEYS } from '@/lib/react-query/queryKeys';
import { jwtDecode } from 'jwt-decode';

// 初始化认证状态
export const initializeAuth = () => {
  const storedToken = JSON.parse(localStorage.getItem(QUERY_KEYS.TOKEN) || 'null');
  if (!storedToken) {
    return { user: null, token: null, isAuthenticated: false };
  }

  const decodedToken = jwtDecode(storedToken.accessToken) as User;
  if (decodedToken.exp && decodedToken.exp * 1000 < Date.now()) {
    localStorage.removeItem(QUERY_KEYS.TOKEN);
    return { user: null, token: null, isAuthenticated: false };
  }

  return { user: decodedToken, token: storedToken, isAuthenticated: true };
};

// 更新认证状态并同步到localStorage
export const updateAuth = (router: any, newState: Partial<{ user: User | null; token: Token | null; isAuthenticated: boolean }>) => {
  router.setContext(old => ({
    ...old,
    auth: { ...old.auth, ...newState },
  }));

  if (newState.token) {
    localStorage.setItem(QUERY_KEYS.TOKEN, JSON.stringify(newState.token));
  } else {
    localStorage.removeItem(QUERY_KEYS.TOKEN);
  }
};

2. 初始化Router Context

import { RouterProvider, createRouter } from '@tanstack/react-router';
import { initializeAuth, updateAuth } from './auth';
import { routes } from './routes';

const router = createRouter({
  routes,
  context: {
    auth: {
      ...initializeAuth(),
      setUser: (user: User | null) => updateAuth(router, { user }),
      setToken: (token: Token | null) => updateAuth(router, { token }),
      setIsAuthenticated: (isAuthenticated: boolean) => updateAuth(router, { isAuthenticated }),
    },
  },
});

3. 在组件中使用Auth状态

import { useRouterContext } from '@tanstack/react-router';

function ProfilePage() {
  const { auth } = useRouterContext();
  
  if (!auth.isAuthenticated) {
    return <div>请先登录</div>;
  }

  return <div>欢迎回来,{auth.user?.name}</div>;
}

4. 在Loader/Action中访问Auth状态

TanStack Router的loader和action可以直接通过context获取认证信息:

export const Route = createFileRoute('/api/profile')({
  loader: async ({ context }) => {
    if (!context.auth.isAuthenticated) {
      throw new Response('Unauthorized', { status: 401 });
    }
    const profile = await fetch(`/api/user/${context.auth.user?.id}`);
    return profile.json();
  },
});

关键注意事项

  • TanStack Router的beforeLoad、loader、action运行在组件外部,无法使用React Hooks,必须通过Router Context获取认证状态。
  • 若混用两种方案,需确保React Context和Router Context的状态同步,避免数据不一致。
  • 除了初始化时检查token过期,还需在API返回401时触发状态重置和登录跳转。

内容的提问来源于stack exchange,提问作者Aniket Tiwari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:57:32