0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ナビゲーションロック用のhook

Posted at

振り返りようです。

// filepath: [useNavigate.ts](http://_vscodecontentref_/0)
import { useCallback, useRef } from "react";
import { useRouter, Href } from "expo-router";

/**
 * ナビゲーションロック用の内部フック
 * @param cooldown クールダウン時間(ミリ秒)
 */
function useNavigationLock(cooldown: number = 500) {
  const isNavigating = useRef(false);
  // ✅ 環境に依存しない型定義
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const runWithLock = useCallback(
    (action: () => void) => {
      // 連打防止
      if (isNavigating.current) {
        if (__DEV__) {
          console.log("⚠️ ナビゲーション中のため、クリックを無視");
        }
        return;
      }

      // ロック開始
      isNavigating.current = true;

      try {
        // アクション実行
        action();
      } catch (error) {
        // エラーログ出力
        if (__DEV__) {
          console.error("❌ ナビゲーションエラー:", error);
        }
      } finally {
        // 🐤 必ずロック解除→例外発生時も確実に実行
        // 既存のタイマーをクリア
        if (timeoutRef.current !== null) {
          clearTimeout(timeoutRef.current);
        }

        // 🐤 型キャスト不要
        timeoutRef.current = setTimeout(() => {
          isNavigating.current = false;
          if (__DEV__) {
            console.log("✅ ナビゲーションロック解除");
          }
        }, cooldown);
      }
    },
    [cooldown]
  );

  return runWithLock;
}

/**
 * push 版
 */
export function useNavigate(cooldown: number = 500) {
  const router = useRouter();
  const runWithLock = useNavigationLock(cooldown);

  const navigate = useCallback(
    (path: Href) => {
      runWithLock(() => {
        router.push(path);
      });
    },
    [router, runWithLock]
  );

  return navigate;
}

/**
 * replace 版
 */
export function useNavigateReplace(cooldown: number = 500) {
  const router = useRouter();
  const runWithLock = useNavigationLock(cooldown);

  const navigate = useCallback(
    (path: Href) => {
      runWithLock(() => {
        router.replace(path);
      });
    },
    [router, runWithLock]
  );

  return navigate;
}

/**
 * back 版
 */
export function useNavigateBack(cooldown: number = 500) {
  const router = useRouter();
  const runWithLock = useNavigationLock(cooldown);

  const goBack = useCallback(() => {
    runWithLock(() => {
      router.back();
    });
  }, [router, runWithLock]);

  return goBack;
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?