1519 단어
8 분
Concurrent Rendering을 활용할 수 있는 React API
2025-10-26

Concurrent Rendering을 활용할 수 있는 React API#

React 18부터는 내부 스케줄러(Fiber Scheduler)가 Concurrent Rendering을 지원하면서 개발자가 렌더링 우선순위를 직접 제어하거나 힌트를 줄 수 있는 다양한 API가 새롭게 추가되었다.

이 API들은 모두 “UI 반응성을 유지하면서 무거운 렌더링이나 비동기 처리를 부드럽게 실행”하는 것을 목표로 한다.


useTransition#

useTransition is a React Hook that lets you render a part of the UI in the background. useTransition은 UI의 특정 부분을 백그라운드에서 렌더링할 수 있도록 하는 React 훅이다.

const [isPending, startTransition] = useTransition();

useTransition 훅의 우선순위 조정#

useTransition은 상태 업데이트를 **낮은 우선순위(Transition 상태)**로 마킹해준다.

React는 모든 상태 업데이트를 Lane(우선순위 트랙)에 배치하여 스케줄링한다. startTransition으로 감싼 업데이트는 TransitionLane에 할당되어 (사용자 입력 등과 같이 높은 우선순위 Lane을 부여 받은 작업보다) 낮은 우선순위로 처리된다.

사용자 입력(setKeyword) → SyncLane (높은 우선순위)
필터링(setFiltered) → TransitionLane (낮은 우선순위)

즉 “지금 바로 반응해야 하는 작업(입력, 클릭)”과 “조금 늦게 반영되어도 되는 작업(리스트 렌더링, 필터링) 결과 표시”를 분리해준다.

📦 사용자 입력 + 검색 필터링 예시#

import { useState, useTransition } from 'react';
function SearchList({ items }) {
const [keyword, setKeyword] = useState("");
const [filtered, setFiltered] = useState(items);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
const value = e.target.value;
setKeyword(value); // 즉시 반영
// 렌더링 여유 있을 때 실행하도록 우선순위 조정
startTransition(() => {
const result = items.filter((item) => item.toLowerCase().includes(value.toLowerCase()));
setFiltered(result);
});
}
return (
<div>
<input value={keyword} onChange={handleChange} />
{isPending && <p>검색 중입니다...</p>}
<ul>
{filtered.map((item) => (
<li key={item.itemId}>{item.name}</li>
))}
</ul>
</div>
)
}

🧠 동작 원리

  • setKeyword즉시 렌더링 (높은 우선순위)
    • 사용자의 입력이 즉각 반영되어 입력 지연이 발생하지 않는다
  • startTransition 내부의 setFiltered → 낮은 우선순위로 스케줄링
    • React는 브라우저가 idle 상태일 때(즉, 여유가 있을 때) 해당 렌더링을 수행한다.
    • 만약 렌더링 도중 새로운 high-priority 이벤트가 발생하면, transition 렌더링은 즉시 중단(yield)되었다가 다시 재개된다.
  • isPendingTransition 상태 동안 true
    • 백그라운드 렌더링이 진행 중임을 나타내며, 로딩 표시 등에 활용할 수 있다

⚡장점

  • ✅ 입력 반응성 유지
    • 무거운 필터링이나 렌더링이 있어도 입력 타이핑 끊김 현상 발생 방지
  • ✅ 부드러운 전환 (Transition)
    • 리스트나 UI 변화가 부드럽게 진행되며, React가 여유 있을 때만 렌더링을 수행
  • ✅ 로딩 상태 표시 가능
    • isPending을 통해 Transition 중임을 감지하여, 스켈레톤 UI, 스피너 등을 표시할 수 있음
  • ✅ Race condition 방지
    • startTransition으로 감싼 비동기 처리(fetch 등)는 렌더링 반영 시점을 조절하기 때문에,
      • 사용자의 빠른 입력 변경과 서버 응답 도착 간의 **UI 불일치 현상(stale UI)**을 줄이는 데 도움이 된다.
      • (단, 네트워크 요청 자체를 취소하려면 AbortController를 병행해야 한다.)

useDeferredValue#

useDeferredValue is a React Hook that lets you defer updating a part of the UI. useDeferredValue는 UI의 특정 부분의 업데이트를 지연시킬 수 있도록 하는 React 훅이다.

const deferredValue = useDeferredValue(value)

공식 문서에 따르면 useDeferredValue는 새로운 콘텐츠가 로딩되는 동안 stale(신선하지 않은 상태)한 콘텐츠를 보여줄 때 사용할 수 있다. (Showing stale content while fresh content is loading)

따라서, useDeferredValue는 **값(value)**을 기반으로 렌더링되는 UI가 있을 때, 그 값을 “조금 늦게 반영”하도록 만들어 UI 반응성을 유지하는 훅이다.

업데이트가 진행될 때, 최초 리렌더링 시에는 이전 값(deferred value)을 그대로 사용하고, 백그라운드에서 새롭게 전달 받은 값을 다음 렌더링 시에 반영함으로서 UI의 상태 불일치를 최소화할 수 있도록 한다.

useDeferredValue 훅의 우선순위 조정#

useTransition과 마찬가지로 useDeferredValue로 생성된 값의 업데이트는 TransitionLane에 매핑된다.

사용자 입력(setKeyword) → SyncLane (높은 우선순위)
필터링(setFiltered) → TransitionLane (낮은 우선순위)

결과적으로 사용자 입력은 즉시 반영하지만 리스트는 조금 늦게 업데이트되는 자연스러운 UX 경험을 제공할 수 있다.

📦 사용자 입력 + 검색 필터링 예시#

import { useState, useDeferredValue } from 'react';
function SearchList({ items }) {
const [keyword, setKeyword] = useState('');
const deferredKeyword = useDeferredvalue(keyword); // 입력값 늦게 반영
const filteredItems = items.filter((item) => item.toLowerCase().includes(deferredQuery.toLowerCase());
return (
<div>
<input value={keyword} onChange={(e) => setKeyword(e.target.value)} />
<ul>
{filteredItems.map((item) => (
<li key={item.itemId}>{item.name}</li>
))}
</ul>
</div>
)
}

🧠 동작 원리

  • setKeyword즉시 렌더링 (높은 우선순위)
    • 사용자의 입력이 즉각 반영되어 입력 지연이 발생하지 않는다
  • deferredQuery → keyword의 지연된 버전
    • React가 브라우저의 렌더링 우선순위를 고려해 **TransitionLane(낮은 우선순위)**로 스케줄링
    • 렌더링이 무거운 경우, React는 사용자 입력이 먼저 처리된 뒤 여유가 있을 때 deferredQuery 기반의 렌더링을 수행

⚡장점

  • ✅ 입력 반응성 유지
    • 무거운 필터링이나 렌더링이 있어도 입력 타이핑 끊김 현상 발생 방지
  • ✅ 렌더링 부하 완화
    • 무거운 필터링, 정렬, 데이터 렌더링 연산을 브라우저가 idle한 시점에 수행 가능
  • ✅ 다른 훅에서 활용 가능
    • useDeferredValue는 React Query, 상태 관리 라이브러리 등에 상태 값에도 적용 가능하여 전역 상태 기반 UI 렌더링 반응성 개선이 가능하다

📚 참고자료#