맹목적으로 useTransition를 아무데나 사용하지 마세요

I
Inkyu Oh

2025.11.13

Nicolas Charpentier 블로그 포스트 번역
2025-11-06



최근에 React의 useTransition 훅에 대해 알아보고 있습니다. React 애플리케이션에서 사용자 경험을 개선하는 데 얼마나 좋은지에 대한 게시물을 계속해서 보고 있기 때문입니다. 이 훅을 사용하여 상태 전환을 더 효과적으로 관리하는 것이 좋다고 하는 게시물을 보았습니다. 특히 느리게 렌더링되는 컴포넌트를 포함한 시나리오에서, 그리고 로딩 상태 핸들러로서도 말이죠.
그래서 자연스럽게 문서를 자세히 살펴보았고, 실망했습니다. 예제가 사용자 경험을 개선하는 것처럼 보이지 않고, 솔직히 말해서 끔찍한 사용자 경험처럼 보였기 때문입니다.
오해하지 마세요. 저는 useTransition이 특히 라우팅에 영향을 미치는 라이브러리를 구축할 때 놀라운 개선이라고 믿습니다. 하지만 어디에나 사용하는 것을 추천한다고요? 남용하기 쉬운 것처럼 보입니다. 제가 놓친 뉘앙스가 있다면, 댓글로 알려주세요!

심층 분석

이유를 이해하기 위해 몇 가지 예제를 단계별로 살펴보겠습니다.

useTransition 없이 기본 예제

React Docs에서 추출한 기본 예제입니다. 왜 useTransition이 필요한지 이해하기 위해 사용을 제거했습니다 (React Docs 기반):
참고 이 예제에서는 느리게 렌더링되는 콘텐츠가 포함된 탭 간 전환 시 간단한 탭 인터페이스가 어떻게 나쁜 사용자 경험을 초래할 수 있는지 볼 수 있습니다: ts (slow)`를 클릭한 후 UI에 피드백이 없습니다. 느리게 렌더링되는 콘텐츠가 전체 스레드를 차단하기 때문입니다. 방법이 없으므로 사용자는 콘텐츠가 로드될 때까지 기다려야 합니다. 다른 것과 상호작용하거나 다른 탭으로 이동하고 싶다면 어떻게 해야 할까요? 느리게 렌더링되는 탭으로의 후속 탐색도 여전히 느립니다.

코드 편집기 로딩 중...

useTransition 도입

React Docs에서 다시 추출한 이 예제에서는 탭 인터페이스에서 useTransition이 어떻게 사용되었는지 볼 수 있습니다.
부모 컴포넌트가 action 내에서 상태를 업데이트하기 때문에, 그 상태 업데이트는 전환으로 표시됩니다. 이는 "Posts"를 클릭한 후 즉시 "Contact"를 클릭할 수 있으며 사용자 상호작용을 차단하지 않는다는 것을 의미합니다. 🔗 출처.
useTransition이 반환하는 isPending 불리언 값을 사용하여 전환이 진행 중임을 사용자에게 알릴 수 있습니다. 예를 들어, 탭 버튼은 특별한 "대기 중" 시각적 상태를 가질 수 있습니다. 🔗 출처.
"Posts"를 클릭하는 것이 이제 더 반응성이 좋아 보입니다. 탭 버튼 자체가 즉시 업데이트되기 때문입니다. 🔗 출처.

코드 편집기 로딩 중...

왜 끔찍해 보이는가

useTransition을 사용하면 렌더링을 중단할 수 있다는 점에서 동의합니다 (이는 매우 유용합니다). 예를 들어, 누군가가 실수로 Posts 탭을 클릭했을 때, 앱은 여전히 반응성이 있으며 다른 곳으로 이동할 수 있습니다.
하지만 isPending을 사용하는 것이 정말로 훌륭한 경험을 제공한다고 생각하지 않습니다. 방금 클릭한 탭이 대기 중임을 나타내지만, 이전 탭은 여전히 활성 상태로 간주되며 이전 탭 콘텐츠를 여전히 볼 수 있습니다. 이는 저에게 훌륭한 사용자 경험처럼 느껴지지 않습니다.
여기서 정말로 선호하는 것은 탭 컴포넌트를 차단하지 않도록 하여 이 컴포넌트를 높은 우선순위로 업데이트한 다음 콘텐츠를 렌더링하는 것입니다.
또 다른 점: 이것이 탐색의 일부라면, 사용자 경험은 여전히 좋지 않습니다. Posts 탭으로 다시 탐색하는 것은 여전히 느립니다. 매번. 브라우저 유휴 시간 동안 백그라운드에서 렌더링되거나, 캐시되거나, 렌더링된 상태로 유지되었을 수 있습니다 (아래에서 다룰 <Activity>를 생각해보세요).
블로그 게시물에서 계속해서 추천하는 것처럼 어디에나 사용해야 하는 이유를 모르겠습니다. 라우팅 라이브러리를 구축하거나 필요한 경우가 아니라면 말이죠. 하지만 그곳에서도 어떻게 사용하는지에 대해 주의해야 한다고 생각합니다.

일반적인 함정

이중 렌더링
전환을 실행하면 두 번의 렌더링이 예약됩니다:
  1. 이전 상태 값으로 대기 상태 (isPending = true)를 표시하기 위한 긴급 렌더링
  1. isPending = false 및 새로운 상태 값으로의 동시 렌더링
  • 이 렌더링이 완료되면 커밋됩니다.
그래서 우리의 컨텍스트에서 비싼 탭을 메모이제이션하는 것이 매우 중요합니다!
facebook/react#24269를 참조하세요.
제어된 입력에는 적합하지 않음
입력 업데이트를 전환으로 래핑할 수 없다는 것을 알고 계셨나요? 입력은 상태를 동기적으로 업데이트해야 하기 때문입니다.
전환은 비차단적이므로 사용자 입력을 즉시 반영해야 하는 제어된 입력에는 적합하지 않습니다.
전환 남용
모든 상태 업데이트를 래핑하면 긴급한 UI 피드백(예: 버튼 클릭, 입력 업데이트)조차 지연될 수 있으며, 따라서 경험이 저하됩니다. 중요한, 비싼 업데이트에만 전환을 사용해야 합니다.

더 나은 솔루션

React에 양보하기

탭 상태에만 집중한다면, 탭 상태를 중요한 업데이트로 처리하여 탭 콘텐츠를 렌더링하는 것이 React에 다시 양보하는 방법 중 하나입니다.
useTransition 없이 기본 예제를 다시 선택하면, 탭 콘텐츠의 렌더링을 다음 이벤트 루프까지 지연시키는 <Delay> 컴포넌트를 사용할 수 있습니다. 주로 첫 번째 렌더링을 건너뛰는 것입니다:
코드 편집기 로딩 중...
<Delay>를 사용하면 탭을 먼저 업데이트한 다음 콘텐츠를 렌더링할 수 있도록 양보하여, 제 생각에는 훨씬 더 나은 사용자 경험을 달성했습니다.
하지만, 또 다른 문제가 있습니다. 이 렌더링을 중단할 수 있는 능력을 잃습니다! Posts 탭을 클릭하면 앱이 멈추고, 그것도 좋은 사용자 경험이 아닙니다. 보세요, 이것은 우리의 옵션을 평가하고 이제 더 나은 제어로 useTransition을 선택할 수 있는 경우입니다.
따라서 <Delay>와 useTransition을 결합하여 두 가지 장점을 모두 얻을 수 있는 방법을 살펴보겠습니다. 이 예제에서는 <Delay>가 전환을 시작하여 탭을 먼저 업데이트한 다음 콘텐츠를 렌더링할 수 있도록 합니다.
보너스로, <Delay>가 전환을 시작하기 때문에, 이번에는 올바른 컨텍스트에서 isPending을 자유롭게 사용하여 콘텐츠 내에서 로딩 상태를 렌더링할 수 있습니다!

참고 우선순위와 우리가 달성하려는 목표에 대한 상기: 한 업데이트: 탭**—훌륭한 사용자 경험을 위해 즉시 업데이트해야 합니다. 우선순위: 게시물 컨테이너**—사용자를 혼동시키지 않기 위해 이전 콘텐츠를 제거하고 새 콘텐츠를 위한 공간을 만들어야 합니다. 우선순위: 게시물 콘텐츠**—이것이 우리가 진정으로 전환이 필요한 실제 백그라운드 렌더링 활동입니다.

코드 편집기 로딩 중...
그래서, React Docs의 예제보다 훨씬 더 나은 사용자 경험이죠? 🙂

<Activity>

또한, <Activity>를 사용하여 UI와 자식의 내부 상태를 숨기고 복원할 수 있는 방법도 있습니다. 🔗 출처.
<Activity>를 통해 Posts의 콘텐츠를 미리 로드하거나, 단순히 렌더링할 수 있지만, 탭을 마운트된 상태로 유지하지만 숨겨진 상태로 유지할 수 있습니다. 렌더링하는 데 비용이 많이 들기 때문입니다.
이 블로그 게시물은 이미 충분히 길기 때문에 더 이상 자세히 설명하지 않겠습니다. <Activity>는 자체 블로그 게시물이 될 수 있으므로, 지금은 React Docs의 🔗 출처를 참조하고 나중에 후속 조치를 취하겠습니다.

2
87

댓글

?

아직 댓글이 없습니다.

첫 번째 댓글을 작성해보세요!