[Hook] useTransition

OlMinJe·2025년 9월 2일

React

목록 보기
18/19

리액트 공식 문서를 참고한 정리 내용 (25.08 기준)

빠른 반응과 무거운 렌더링을 분리해, 앱이 끊기지 않고 부드럽게 동작하도록 도와주는 Hook이다.

보통
(1) 즉각 반응해야 하는 업데이트(입력창 타이핑 등)와
(2) 조금 느려도 괜찮은 업데이트(큰 리스트 렌더링 등)를 구분하여 처리할 수 있게 해준다.

const [isPending, startTransition] = useTransition()

컴포넌트의 최상위 수준에서 useTransition을 호출하여 일부 state 업데이트를 Transition 으로 표시한다.

import { useTransition } from 'react';

function TabContainer() {
  const [isPending, startTransition] = useTransition();
  // ...
}

매개변수

없다.


반환값

useTransition은 두 가지 값을 배열로 반환한다.

isPending

  • 현재 Transition이 진행 중인지 알려주는 불리언 값 (로딩 상태 표시 등에 사용)

startTransition(action)

  • 특정 state 업데이트를 Transition(덜 급한 업데이트) 으로 처리할 수 있게 해주는 함수.
  • useTransition이 반환하는 startTransition 함수는 특정 상태 업데이트를 Transition(전환) 으로 표시할 수 있게 해준다.
  • Transition으로 표시된 업데이트는 우선순위가 낮게 처리되며, UI가 끊기지 않고 부드럽게 반응할 수 있도록 도와준다.
function TabContainer() {
  const [isPending, startTransition] = useTransition();
  const [tab, setTab] = useState('about');

 function selectTab(nextTab) {
    startTransition(() => {
      setTab(nextTab); // 이 업데이트는 Transition으로 처리됨
    });
  }

  return (
    <>
      <button onClick={() => selectTab('about')}>About</button>
      <button onClick={() => selectTab('contact')}>Contact</button>
      {isPending && <p>로딩 중...</p>}
    </>
  );
}

🔎 Transition은 non-blocking 업데이트로 불필요한 로딩 UI가 생기지 않으며, 보통 무거운 UI 변경(예: 리스트 필터링, 탭 전환) 시 사용자 입력은 즉시 반응하면서 UI 업데이트는 천천히 진행되도록 할 때 유용하다.

매개변수

action

  • 하나 이상의 set 함수를 실행하는 함수로
  • React는 이 action 내부에서 예약된 상태 업데이트를 Transition 업데이트로 인식한다.
  • await 이후의 set은 자동으로 Transition에 포함되지 않기 때문에, 필요하다면 추가로 startTrnsition으로 감싸야 한다.

반환값

없다.


주의사항

Hook 안에서만 사용 가능

  • useTransition은 React Hook이므로 반드시 컴포넌트나 커스텀 Hook 안에서만 호출해야 하며, 외부 라이브러리나 일반 함수에서는 쓸 수 없다.

setTimeout 같은 비동기 안에서는 적용 안 됨

  • startTransition 안에 있는 함수는 즉시 실행되면서 그 안의 setState를 Transition으로 표시한다.
  • 하지만 setTimeout 같은 비동기 함수 안에서 실행하면 Transition으로 인식되지 않기 때문에,
  • 비동기 이후 상태 업데이트를 Transition으로 처리하려면 다시 startTransition으로 감싸야 한다.

동기 실행만 가능

  • startTransition은 동기적으로 실행되어야 하며, 함수 실행 중에 발생한 모든 상태 업데이트만 Transition으로 처리된다.
  • 즉, "나중에 실행할 상태 변경"은 Transition으로 표시되지 않음.

Effect 의존성과는 무관

  • startTransition은 안정적인 식별성을 가지므로 useEffect 의존성 배열에 넣을 필요가 없다. (경고가 뜨더라도 실제 동작에는 문제 없음)

Transition은 다른 업데이트에 의해 취소될 수 있음

  • Transition 업데이트는 입력 같은 즉각 반응 업데이트보다 우선순위가 낮아 덕분에 UI가 끊기지 않고 자연스럽게 반응한다

입력 제어에는 사용 불가

  • 입력은 지연 없이 즉시 반영되어야 하기 때문에, useTransition은 텍스트 입력 같은 즉시 반으이 필요한 곳에 사용하면 X

여러 Transition은 병합됨

  • 동시에 여러 개의 Transition이 발생하면 React가 알아서 묶어 처리하기 때문에, 세세하게 나눌 필요는 없다.

👉 정리하자면, useTransition은 무거운 UI 업데이트를 부드럽게 만들어주지만, 즉시 반응이 필요한 입력에는 쓰지 말고, 항상 동기 실행 안에서만 사용해야 한다.


사용법

Actions으로 non-blocking 업데이트 수행

useTransition()으로 반환된 startTransition(action)을 사용해 action 내부의 상태 업데이트를 non-blocking 방식으로 표시할 수 있다.

import {useState, useTransition} from 'react';

function CheckoutForm() {
  const [isPending, startTransition] = useTransition();
  
  const onClick = () => startTransition(() => setTab('posts'));
}

이렇게 하면, UI 반응성이 유지되면서도 백그라운드에서 상태가 조용히 바뀐다.


컴포넌트에서 Action 프로퍼티를 노출하기

컴포넌트가 action 프로퍼티를 받아 부모로부터 전달된 로직을 Transition으로 감쌀 수 있다.

function TabButton({ action }) {
  const [isPending, startTransition] = useTransition();
  return (
    <button onClick={() => startTransition(action)}>
      {isPending ? '...' : 'Go'}
    </button>
  );
}

action이 sync/async 모두 작동하고, 사용자 입력에 대한 반응을 즉시 유지할 수 있다.


대기 상태를 시각적으로 표현하기

isPending 플래그를 통해 Transition 진행 중임을 UI로 표시할 수 있다.

if (isPending) {
  return <button className="pending">Loading…</button>;
}

이런 방식으로, 사용자가 무슨 일이 일어나고 있는지 명확하게 볼 수 있다.


원치 않는 로딩 표시기 방지

Transition과 Suspense가 겹칠 때는 과도한 로딩 UI가 나올 수 있다.
그러니 Transition은 isPending이나 useOptimistic 같은 훅을 사용한 내부적으로 처리하는 것이 좋다.

--

Suspense-enabled 라우터 구축

useTransitionSuspense를 조합하여 라우팅 시 UX 끊김 최소화하는 구조를 만들 수 있다.

<Suspense fallback={<Loader />}>
  <TabButton action={() => setTab('posts')} />
</Suspense>

Transition과 Suspense를 고르게 배치하면 페이지 전환이 더 부드러워 진다고 하네


Error boundary로 사용자에게 오류 표시하기 

데이터를 추가하다가 오류가 발생하면 ErrorBoundary를 통해 아름답게(?!) 처리할 수 있다.

<ErrorBoundary fallback={<div>오류 발생!</div>}>
  <AddCommentButton />
</ErrorBoundary>

isPending 상태로 버튼을 비활성화하고, 오류는 사용자에게 깔끔하게 보여줄 수 있다.

profile
큐트걸

1개의 댓글

comment-user-thumbnail
2025년 9월 19일

좋은 글 감사합니다!👍👍

답글 달기