HooneyLog
© 2026 Seunghoon Shin. All rights reserved.
모든 게시글
react
2022. 7. 24.•
1

React 18 useTransition: 긴 작업을 분리하여 사용자 경험(UX) 극대화하기

Seunghoon Shin
작성자 Seunghoon Shin풀스택 개발자

React 18 useTransition: 긴 작업을 분리하여 사용자 경험(UX) 극대화하기

1. 문제의 배경

React 앱에서 사용자의 입력을 실시간으로 반영하면서 동시에 무거운 계산이나 대량의 데이터 필터링을 수행해야 하는 경우가 있습니다. 예를 들어 검색창에 타이핑할 때마다 수천 개의 목록을 필터링하여 보여주는 시나리오를 생각해 봅시다.

기존의 React에서는 모든 상태 업데이트가 동일한 우선순위를 가졌습니다. 따라서 무거운 필터링 작업이 진행되는 동안 브라우저의 메인 스레드가 점유되어, 사용자가 타이핑하는 글자가 화면에 즉시 나타나지 않고 버벅거리는 현상(Input Lag)이 발생하게 됩니다. 이는 사용자에게 매우 좋지 않은 경험을 제공합니다.

2. 해결 방안 탐색

이 문제를 해결하기 위해 과거에는 debounce나 throttle 기법을 사용해 업데이트 빈도를 인위적으로 조절하곤 했습니다. 하지만 이는 근본적인 해결책이 아니며, 여전히 실제 업데이트가 일어날 때는 화면이 멈추는 현상을 피하기 어렵습니다.

React 18은 동시성(Concurrency) 모드를 도입하며 이 문제에 대한 근본적인 해결책인 useTransition Hook을 선보였습니다. 핵심 아이디어는 "업데이트의 우선순위를 나누는 것"입니다. 즉각적인 피드백이 필요한 입력값 업데이트는 높은 우선순위를 주고, 결과 목록을 렌더링하는 무거운 작업은 낮은 우선순위로 밀어내는 전략입니다.

3. 핵심 개념 및 아키텍처

useTransition은 상태 업데이트를 '전환(Transition)'으로 표시합니다. 전환 업데이트는 긴급한 업데이트(예: 입력창 타이핑)에 의해 중단될 수 있으며, 백그라운드에서 렌더링이 진행됩니다.

  • Urgent Update: 타이핑, 클릭 등 즉각적인 물리적 반응이 필요한 작업.
  • Transition Update: 데이터를 필터링하거나 화면을 전환하는 등 약간의 지연이 허용되는 작업.

4. 구현 및 트러블슈팅

useTransition은 isPending 상태와 startTransition 함수를 반환합니다.

실제 구현 예시

import { useState, useTransition } from 'react'; function SearchComponent() { const [isPending, startTransition] = useTransition(); const [query, setQuery] = useState(""); const [list, setList] = useState([]); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const value = e.target.value; // 1. 긴급 업데이트: 입력창에 글자가 즉시 입력됨 setQuery(value); // 2. 전환 업데이트: 무거운 리스트 필터링은 낮은 우선순위로 처리 startTransition(() => { // 대량의 데이터를 처리하는 무거운 로직 const filtered = largeData.filter(item => item.includes(value)); setList(filtered); }); }; return ( <div> <input type="text" value={query} onChange={handleChange} /> {/* 데이터 로딩 중임을 사용자에게 알림 */} {isPending && <p>목록을 갱신 중입니다...</p>} <ul> {list.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> </div> ); }

주의사항 (Troubleshooting)

  • startTransition 내부에는 상태 업데이트 함수만 넣어야 합니다. setTimeout이나 API 호출 같은 비동기 작업 자체를 넣는 것이 아니라, 비동기 작업의 결과를 상태에 반영하는 부분을 감싸야 합니다.
  • 제어 컴포넌트의 value 업데이트를 startTransition으로 감싸면 안 됩니다. 입력창이 반응하지 않게 될 수 있습니다.

5. 결과 및 Trade-off

결과

  • 응답성 극대화: 무거운 작업 중에도 사용자의 입력은 항상 즉각적으로 반응합니다.
  • UX 향상: isPending을 통해 작업이 진행 중임을 자연스럽게 알릴 수 있습니다.

Trade-off

  • 렌더링 횟수: 하나의 작업이 여러 번의 렌더링 단계를 거치게 되어 CPU 자원을 더 많이 사용할 수 있습니다.
  • 복잡성: 상태가 일시적으로 불일치할 수 있으므로(입력값은 바뀌었는데 목록은 이전 것인 상태), 이에 대한 UI적인 처리가 필요합니다.

6. 마치며

useTransition은 React 18 동시성의 힘을 가장 체감하기 좋은 도구입니다. 모든 작업이 긴급할 필요는 없다는 사실을 이해하고 우선순위를 적절히 배분한다면, 훨씬 더 부드럽고 전문적인 웹 애플리케이션을 만들 수 있을 것입니다.

참고 자료:

  • React Docs: useTransition
  • React 18: New APIs and Features
← 이전 글Authorization Guard 하는 방법
다음 글 →Basic and Useful React Custom Hooks