본문 바로가기
C.W.K.
Stream
Lesson 01 of 06 · published

useTransition — 비긴급 상태 업데이트

~12 min · usetransition, concurrent, priority

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
키 입력은 즉시 반응해야 하지만 큰 결과 목록은 조금 늦어도 돼. useTransition으로 긴급한 업데이트와 미뤄도 되는 업데이트를 구분해.

기본 모양

const [isPending, startTransition] = useTransition()을 호출하고, 미뤄도 되는 상태 변경을 startTransition(() => setX(...))로 감싸. React는 그 변경을 낮은 우선순위로 처리하고, isPending은 아직 끝나지 않은 transition이 있는지 알려 줘.

검색 입력과 결과 목록을 분리해

검색창의 글자는 누르는 즉시 바뀌어야 하지만, 새 검색어로 수천 개 항목을 거르는 결과 목록은 조금 뒤따라와도 괜찮아. 입력 상태는 바로 갱신하고 결과 상태만 transition으로 바꾸면 키 입력은 막히지 않고 무거운 목록은 백그라운드에서 새 결과를 준비해.

Suspense와 함께 쓰면 이전 화면을 지킬 수 있어

상태 변경 때문에 자식이 중단되면 보통 Suspense의 대체 UI가 나타날 수 있어. 그 변경을 transition으로 표시하면 React는 새 화면이 준비될 때까지 이전 내용을 유지해. 화면 전체를 빈 로딩 상태로 바꾸는 대신 isPending으로 상단 진행 막대나 옅은 표시를 보여 줄 수 있어.

비동기 작업 자체를 감싸지는 마

startTransition 안에는 우선순위를 낮출 상태 변경을 넣어. fetch나 타이머 같은 비동기 작업은 밖에서 실행하고, 결과를 상태에 반영하는 부분만 감싸면 돼.

const data = await fetchResults(query);
startTransition(() => setResults(data));
우선순위는 작성자가 알려 줘야 해. React는 어떤 변경이 입력만큼 급한지 스스로 알 수 없어. useTransition은 사용자의 조작을 먼저 지키고, 늦어도 되는 화면 갱신은 뒤로 미루겠다는 의도를 표현해.

입력 자체를 transition으로 늦추지 마

제어되는 input의 value를 바꾸는 상태는 즉시 반영해야 커서와 타이핑이 자연스러워. 검색어 state는 바로 바꾸고 그 값으로 만드는 무거운 결과 state만 startTransition 안에서 갱신해.

Transition 작업은 더 긴급한 입력이 오면 중단됐다가 최신 값으로 다시 시작될 수 있어. 중간 렌더링이 화면에 확정되지 않을 수 있으므로 렌더링 중 부수 효과를 실행하면 안 돼.

Code

Transition으로 입력 반응을 유지하는 검색·tsx
import { useState, useTransition } from "react";

function SearchPage() {
  const [query, setQuery] = useState("");
  const [results, setResults] = useState<string[]>([]);
  const [isPending, startTransition] = useTransition();

  function onInput(value: string) {
    setQuery(value); // 긴급 — input 즉시 업데이트
    startTransition(() => {
      // 비긴급 — 10k 결과 렌더가 타이핑 안 막음
      setResults(filterMassiveDataset(value));
    });
  }

  return (
    <div>
      <input value={query} onChange={(e) => onInput(e.target.value)} />
      {isPending && <p className="text-muted text-sm">Updating…</p>}
      <ul style={{ opacity: isPending ? 0.6 : 1 }}>
        {results.map((r) => <li key={r}>{r}</li>)}
      </ul>
    </div>
  );
}

function filterMassiveDataset(_q: string): string[] {
  // 상상: 10,000 row, 필터링 + 정렬.
  return [];
}
Transition으로 Suspense 화면 전환을 부드럽게·tsx
import { Suspense, useState, useTransition } from "react";

function TabbedView() {
  const [tab, setTab] = useState<"a" | "b">("a");
  const [isPending, startTransition] = useTransition();

  function switchTab(next: "a" | "b") {
    // startTransition 없으면: 탭 스위치가 Suspense 대체 UI flash.
    // 있으면: 새 탭 데이터 resolve 까지 이전 탭 보이게 유지.
    startTransition(() => setTab(next));
  }

  return (
    <div>
      <nav className="flex gap-2" style={{ opacity: isPending ? 0.6 : 1 }}>
        <button onClick={() => switchTab("a")}>A</button>
        <button onClick={() => switchTab("b")}>B</button>
      </nav>
      <Suspense fallback={<p>Loading…</p>}>
        {tab === "a" ? <TabA /> : <TabB />}
      </Suspense>
    </div>
  );
}

function TabA() { return <p>A</p>; }
function TabB() { return <p>B</p>; }

External links

Exercise

입력한 문자열로 5천 개 항목을 거르는 검색 화면을 만들어. 먼저 일반 상태 업데이트에서 입력이 늦어지는지 확인한 뒤, 결과 목록의 업데이트만 useTransition으로 감싸. isPending일 때 목록을 옅게 표시해 새 결과를 준비 중이라는 사실도 보여 줘.
Hint
항목은 Array.from으로 만들고 includes로 걸러. 입력 상태는 즉시 갱신하고 결과 상태만 startTransition 안에서 바꿔.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.