React Router の useNavigate と navigate(0) について

今回は React Routerでよく使用されるuseNavigateについて詳しく解説していきます。

useNavigate とは?

React Router の useNavigate は、Reactアプリケーションでプログラムによる画面遷移を実現するための強力な Hook です。以前は history API を使用していましたが、現在は useNavigate が推奨される方法となっています。

基本的な使い方

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

function LoginComponent() {
  const navigate = useNavigate();

  const handleLogin = async (e) => {
    e.preventDefault();
    // ログイン処理
    const success = await loginUser();

    if (success) {
      // ログイン成功時にダッシュボードへ遷移
      navigate('/dashboard');
    }
  };

  return (
    <form onSubmit={handleLogin}>
      {/* フォームの内容 */}
    </form>
  );
}

useNavigate の便利な使い方

1. データを渡しながら画面遷移

const navigate = useNavigate();

// ユーザー情報を次の画面に渡す
navigate('/profile', { 
  state: { 
    userId: 123,
    username: "John"
  } 
});

2. 履歴の操作

// 1つ前の画面に戻る
navigate(-1);

// 2つ前の画面に戻る
navigate(-2);

// 1つ先の画面に進む
navigate(1);

useNavigate の実践的なユースケース

開発でよく使用される useNavigate のユースケースを実例とともに解説します。

1. ログイン/認証後のリダイレクト

function LoginForm() {
  const navigate = useNavigate();
  const [error, setError] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const result = await loginUser(credentials);
      if (result.success) {
        navigate('/dashboard', { 
          replace: true, // ブラウザの履歴を置き換え(戻るボタンでログイン画面に戻れなくする)
          state: { userName: result.user.name }
        });
      }
    } catch (error) {
      setError('ログインに失敗しました');
    }
  };

  return <form onSubmit={handleSubmit}>{/* フォームの内容 */}</form>;
}

2. フォーム送信後の遷移

function OrderForm() {
  const navigate = useNavigate();

  const handleSubmit = async (formData) => {
    const orderId = await submitOrder(formData);

    // 注文完了ページへ遷移し、注文情報を渡す
    navigate(`/order/complete/${orderId}`, {
      state: {
        orderDetails: formData,
        timestamp: new Date().toISOString()
      }
    });
  };

  return (/* フォームの内容 */);
}

3. 権限チェックと条件付きリダイレクト

function AdminDashboard() {
  const navigate = useNavigate();
  const { user } = useAuth();

  useEffect(() => {
    if (!user || !user.isAdmin) {
      navigate('/forbidden', {
        replace: true,
        state: { message: '管理者権限が必要です' }
      });
    }
  }, [user, navigate]);

  return (/* ダッシュボードの内容 */);
}

4. 複数ステップのフォーム処理

function MultiStepForm() {
  const navigate = useNavigate();
  const { step, formData } = useFormContext();

  const handleNext = () => {
    if (step === 1) {
      navigate('/form/step2', { state: { formData } });
    } else if (step === 2) {
      navigate('/form/review', { state: { formData } });
    }
  };

  const handleBack = () => {
    navigate(-1); // 前のステップに戻る
  };

  return (/* フォームの内容 */);
}

5. データ検索と結果ページへの遷移

function SearchComponent() {
  const navigate = useNavigate();

  const handleSearch = (searchParams) => {
    const queryString = new URLSearchParams(searchParams).toString();
    navigate({
      pathname: '/search',
      search: `?${queryString}`,
    });
  };

  return (/* 検索フォームの内容 */);
}

6. エラー発生時のリダイレクト

function ProductDetail() {
  const navigate = useNavigate();

  useEffect(() => {
    const fetchProduct = async () => {
      try {
        const product = await getProduct(id);
        if (!product) {
          navigate('/404', { replace: true });
        }
      } catch (error) {
        navigate('/error', { 
          replace: true,
          state: { error: error.message }
        });
      }
    };

    fetchProduct();
  }, [id, navigate]);

  return (/* 商品詳細の内容 */);
}

7. ショッピングカートのチェックアウトフロー

function CartCheckout() {
  const navigate = useNavigate();
  const { cart } = useCart();

  const handleCheckout = () => {
    if (cart.items.length === 0) {
      navigate('/cart', {
        replace: true,
        state: { message: 'カートが空です' }
      });
      return;
    }

    if (!isUserLoggedIn()) {
      navigate('/login', {
        state: { 
          returnTo: '/checkout',
          message: 'チェックアウトにはログインが必要です'
        }
      });
      return;
    }

    navigate('/checkout');
  };

  return (/* チェックアウトボタンなど */);
}

8. フィルタリングと並び替え

function ProductList() {
  const navigate = useNavigate();
  const location = useLocation();

  const handleFilter = (filters) => {
    navigate({
      pathname: location.pathname,
      search: `?${new URLSearchParams(filters).toString()}`,
    }, {
      replace: true // URLの履歴を残したくない場合
    });
  };

  return (/* 商品一覧とフィルターUI */);
}

これらのユースケースを適切に組み合わせることで、スムーズなユーザー体験を実現できます。また、パフォーマンスやSEOを考慮して、適切な場面で navigate を使用することが重要です。

ついでにnavigate(0) の特徴

さて、ここからが本題の navigate(0) についてです。

navigate(0) とは?

navigate(0) は現在のページを完全にリロードする機能です。window.location.reload() と同様の動作をしますが、React Router の文脈の中で使用できる利点があります。

navigate(0) の使用例

function DataListComponent() {
  const navigate = useNavigate();

  const handleRefresh = () => {
    // データを最新の状態に更新
    navigate(0);
  };

  return (
    <div>
      <button onClick={handleRefresh}>
        データを更新
      </button>
      {/* データ一覧の表示 */}
    </div>
  );
}

navigate(0) のユースケース

  1. フォームの送信後にページをリフレッシュしたい場合
  2. データの変更後に最新の状態を表示したい場合
  3. アプリケーションの状態をリセットしたい場合

navigate(0) vs window.location.reload()

両者は似たような動作をしますが、いくつかの違いがあります:

  1. 履歴の扱い
  • navigate(0) は React Router の文脈の中で動作する
  • window.location.reload() はブラウザネイティブの機能
  1. React の文脈
  • navigate(0) は React のライフサイクルを考慮している
  • window.location.reload() は単純なページリロード

まとめ

useNavigate と navigate(0) は、モダンな React アプリケーションで画面遷移とページリロードを扱うための強力なツールです。

  • useNavigate はプログラムによる画面遷移に
  • navigate(0) は現在のページの完全なリロードに
  • 両者を組み合わせることで、よりスムーズなユーザー体験を実現できます

コメントを残す