Skip to content

React Router v6 でのリダイレクト方法

React Router v6 では、リダイレクトの実装方法が v5 から大きく変更されました。この記事では、v6 での効果的なリダイレクト方法を詳しく解説します。

問題点

React Router v6 では、v5 で使用されていた Redirect コンポーネントや Routerender プロパティが削除されました。以下のコードは v5 では動作しましたが、v6 ではエラーが発生します:

jsx
<Route render={() => <Navigate to="/" />} />

エラーメッセージ:

Property 'render' does not exist on type 'IntrinsicAttributes & (PathRouteProps | LayoutRouteProps | IndexRouteProps)'.

解決策

1. Navigate コンポーネントを使用する

React Router v6 では、Redirect コンポーネントの代わりに Navigate コンポーネントを使用します。

jsx
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/lab" element={<Lab />} />
    <Route path="*" element={<Navigate to="/" replace />} />
  </Routes>
</BrowserRouter>

TIP

replace プロパティを使用すると、ブラウザの履歴に現在のページを残さないため、ユーザーが「戻る」ボタンを押した際に余計なリダイレクトが発生しません。

2. 条件付きリダイレクト

ユーザーの認証状態などに基づいた条件付きリダイレクトも簡単に実装できます:

jsx
<Route 
  path="/login" 
  element={user ? <Navigate to="/" replace /> : <Login />} 
/>
<Route 
  path="/dashboard" 
  element={user ? <Dashboard /> : <Navigate to="/login" replace />} 
/>

3. カスタムリダイレクトコンポーネント

より複雑なリダイレクトが必要な場合、カスタムコンポーネントを作成できます:

jsx
import { useEffect } from 'react';
import { generatePath, useNavigate, useParams } from 'react-router-dom';

function Redirect({ to }: { to: string }) {
  const navigate = useNavigate();
  const params = useParams();

  useEffect(() => {
    navigate(generatePath(to, params), { replace: true });
  }, [navigate, to, params]);

  return null;
}

// 使用例
<Route path="/users/:id" element={<Redirect to="/new-path/:id" />} />

このコンポーネントは、パスパラメータを保持したままリダイレクトを行います(例: /users/10/new-path/10)。

4. プログラムによるリダイレクト

イベントハンドラー内でリダイレクトを行う場合は、useNavigate フックを使用します:

jsx
import { useNavigate } from 'react-router-dom';

function MyComponent() {
  const navigate = useNavigate();
  
  const handleRedirect = () => {
    navigate('/target-path', { replace: true });
  };
  
  return (
    <button onClick={handleRedirect}>移動する</button>
  );
}

認証ガードパターン

保護されたルートを実装する際は、高階コンポーネントパターンが便利です:

jsx
import { useLocation, Navigate } from 'react-router-dom';
import { useAuth } from '../hooks/Auth';

export function RequireAuth({ children }: { children: JSX.Element }) {
  let { user } = useAuth();
  let location = useLocation();

  if (!user) {
    return <Navigate to="/login" state={{ from: location }} replace />;
  }
  
  return children;
}

// 使用例
<Route
  path="/dashboard"
  element={
    <RequireAuth>
      <Dashboard />
    </RequireAuth>
  }
/>

よくある間違いと回避策

WARNING

Navigate コンポーネントを条件なしで直接レンダリングすると、無限ループが発生する可能性があります。条件付きレンダリングや useEffect 内での使用を検討してください。

jsx
// 悪い例 - 無限ループの可能性
{!user && <Navigate to="/login" />}

// 良い例 - useEffect 内で処理
useEffect(() => {
  if (!user) {
    navigate('/login', { replace: true });
  }
}, [user, navigate]);

まとめ

React Router v6 でのリダイレクトは、主に以下の方法で実装します:

  1. Navigate コンポーネント - 宣言的なリダイレクト
  2. useNavigate フック - プログラム的なナビゲーション
  3. カスタムコンポーネント - 特殊なリダイレクト要件に対応

適切な方法を選択し、ユーザーエクスペリエンスを考慮したリダイレクト実装を心がけましょう。