Vite + TanStack Router - 6. 認証付きルートの設定
外部の認証サービスを使っている場合、useAuth()
などのフックを使ってユーザーのログイン状態を取得することになりますが、フックはコンポーネント内でしか使えないため、 createFileRoute
のbeforeLoad
では呼び出せません。
そのため、あらかじめ認証状態を取得し、RouterContext
を使って各ルートに伝えるようにします。
手順としては以下のようになります。
RootRoute
をContext付きで作成<App />
コンポーネントで認証状態を取得し、Contextにセット- 各ページで
context
を参照し、認証状態を確認
1. RootRoute
をContext付きで作成
src/routes/__root.tsx
ファイルでルーターを初期化する際に、createRootRoute
ではなく、createRootRouteWithContext
を使います。
この例ではAuth0を例としてあげています、Auth0の部分はご利用のSaaSに置き換えてください。
import { createRootRouteWithContext, Outlet } from "@tanstack/react-router";import { useAuth0 } from '@auth0/auth0-react';
//...
type RouterContext = { auth: ReturnType<typeof useAuth0>; };
export const Route = createRootRouteWithContext<RouterContext>()({ component: () => <Outlet />, // 省略可 });
//...
注意点として createRootRouteWithContext
は2回呼ぶ必要があります。
createRootRoute() // ()1回createRootRouteWithContext<T>()() // ()2回
2. <App />
コンポーネントで認証状態を取得し、contextにセット
App.tsx
で useAuth0
を呼び出して認証状態を取得し、RouterContext
にセットします。
import { RouterProvider, createRouter } from "@tanstack/react-router";import { useAuth0 } from '@auth0/auth0-react';import { routeTree } from "./routeTree.gen";import "./App.css";
const router = createRouter({ routeTree, context: { auth: undefined!, },});
declare module "@tanstack/react-router" { interface Register { router: typeof router; }}
function App() { const auth = useAuth0(); return ( <> <RouterProvider router={router} context={{auth}} /> </> );}
export default App;
3. 各ページでcontext
を参照し、認証状態を確認
adminページで beforeLoad
で認証状態をContextから読み出し、ログインしていなければredirect()
をスローしてログイン画面に遷移します。
import { createFileRoute, redirect } from '@tanstack/react-router'
export const Route = createFileRoute('/admin')({ beforeLoad: ({ context, location }) => { if (!context.auth.isAuthenticated) { throw redirect({ to: '/login', search: { redirect: location.href, }, }) } },})
まとめ
beforeLoad
でフックは使えないので、認証状態はContextに入れておく必要がある- Contextを使うには
createRootRouteWithContext
でルートを作る createRootRouteWithContext
は高階関数なので戻り値を再度呼ぶ必要がる