Docs
API
Hooks
useBlocker

useBlocker hook

useBlocker 메서드는 탐색 차단을 조건이 충족될 때 구현하는 hook입니다.

⚠️ 새로운 useBlocker API는 현재 실험적입니다.

useBlocker options

useBlocker hook은 하나의 필수 인수로 옵션 객체를 받습니다:

options.shouldBlockFn option

  • 필수
  • 타입: ShouldBlockFn
  • 이 함수는 차단기가 현재 탐색을 차단해야 하는지를 나타내는 boolean 또는 Promise<boolean>을 반환해야 합니다.
  • 함수는 ShouldBlockFnArgs 타입의 인수를 전달받으며, 이는 현재 및 다음 route와 수행된 작업에 대한 정보를 제공합니다.
  • 이 함수를 라우터가 탐색을 차단해야 하는지를 알려주는 역할로 생각하세요. 따라서 true를 반환하면 탐색을 차단하고, false를 반환하면 탐색이 허용됩니다.
interface ShouldBlockFnLocation<...> {
  routeId: TRouteId
  fullPath: TFullPath
  pathname: string
  params: TAllParams
  search: TFullSearchSchema
}
 
type ShouldBlockFnArgs = {
  current: ShouldBlockFnLocation
  next: ShouldBlockFnLocation
  action: HistoryAction
}

options.disabled option

  • 선택적 - 기본값: false
  • 타입: boolean
  • 차단기를 완전히 비활성화할지 여부를 지정합니다.

options.enableBeforeUnload option

  • 선택적 - 기본값: true
  • 타입: boolean | (() => boolean)
  • 브라우저의 beforeUnload 이벤트를 항상 또는 조건부로 차단할지 여부를 설정합니다.

options.withResolver option

  • 선택적 - 기본값: false
  • 타입: boolean
  • hook에서 반환된 resolver를 사용할지 또는 shouldBlockFn 함수 자체가 차단을 해결할지를 지정합니다.

options.blockerFn option (⚠️ deprecated)

  • 선택적
  • 타입: BlockerFn
  • 탐색을 허용할지 여부를 나타내는 boolean 또는 Promise<boolean>을 반환하는 함수입니다.

options.condition option (⚠️ deprecated)

  • 선택적 - 기본값: true
  • 타입: boolean
  • 이 조건이 true일 때 탐색 시도가 차단됩니다.

useBlocker returns

탐색의 수동 차단 및 차단 해제를 제어할 수 있는 객체를 반환합니다.

  • status - 'blocked' 또는 'idle' 중 하나인 문자열 리터럴
  • next - statusblocked일 때, 다음 위치에 대한 정보를 포함하는 타입 내로잉 가능한 객체
  • current - statusblocked일 때, 현재 위치에 대한 정보를 포함하는 타입 내로잉 가능한 객체
  • action - statusblocked일 때, 탐색을 트리거한 작업을 나타내는 HistoryAction 문자열
  • proceed - statusblocked일 때, 탐색을 계속할 수 있는 함수
  • reset - statusblocked일 때, 탐색을 취소하는 함수 (status'idle'로 재설정됩니다)

또는

withResolverfalse일 때 void

Examples

useBlocker hook의 일반적인 두 가지 사용 사례:

Basic usage

import { useBlocker } from "@tanstack/react-router";
 
function MyComponent() {
  const [formIsDirty, setFormIsDirty] = useState(false);
 
  useBlocker({
    shouldBlockFn: () => formIsDirty,
  });
 
  // ...
}

Custom UI

import { useBlocker } from "@tanstack/react-router";
 
function MyComponent() {
  const [formIsDirty, setFormIsDirty] = useState(false);
 
  const { proceed, reset, status, next } = useBlocker({
    shouldBlockFn: () => formIsDirty,
    withResolver: true,
  });
 
  // ...
 
  return (
    <>
      {/* ... */}
      {status === "blocked" && (
        <div>
          <p>{next.pathname}로 이동 중입니다.</p>
          <p>정말로 떠나시겠습니까?</p>
          <button onClick={proceed}>예</button>
          <button onClick={reset}>아니오</button>
        </div>
      )}
    </>
  );
}

Conditional blocking

import { useBlocker } from "@tanstack/react-router";
 
function MyComponent() {
  const { proceed, reset, status } = useBlocker({
    shouldBlockFn: ({ next }) => {
      return !next.pathname.includes("step/");
    },
    withResolver: true,
  });
 
  // ...
 
  return (
    <>
      {/* ... */}
      {status === "blocked" && (
        <div>
          <p>정말로 떠나시겠습니까?</p>
          <button onClick={proceed}>예</button>
          <button onClick={reset}>아니오</button>
        </div>
      )}
    </>
  );
}

Without resolver

import { useBlocker } from "@tanstack/react-router";
 
function MyComponent() {
  const [formIsDirty, setFormIsDirty] = useState(false);
 
  useBlocker({
    shouldBlockFn: ({ next }) => {
      if (next.pathname.includes("step/")) {
        return false;
      }
 
      const shouldLeave = confirm("정말로 떠나시겠습니까?");
      return !shouldLeave;
    },
  });
 
  // ...
}

Type narrowing

import { useBlocker } from "@tanstack/react-router";
 
function MyComponent() {
  const [formIsDirty, setFormIsDirty] = useState(false);
 
  // editor-1에서 /foo/123?hello=world로 이동을 차단
  const { proceed, reset, status } = useBlocker({
    shouldBlockFn: ({ current, next }) => {
      if (
        current.routeId === "/editor-1" &&
        next.fullPath === "/foo/$id" &&
        next.params.id === "123" &&
        next.search.hello === "world"
      ) {
        return true;
      }
      return false;
    },
    enableBeforeUnload: false,
    withResolver: true,
  });
 
  // ...
}