동시성 모드(react)

React 18에서 도입된 렌더링 작업을 중단·재개·우선순위 조정할 수 있는 렌더링 방식입니다.

기존 렌더링 vs 동시성 모드

기존 렌더링 (동기)
→ 한번 시작하면 끝날 때까지 멈출 수 없음
→ 렌더링 중 사용자 입력 → 반응 없음 (버벅임)

시간 →
[------렌더링 중 (중단 불가)------] [사용자 입력 처리]

동시성 모드 (비동기)
→ 렌더링을 잘게 쪼개서 중단/재개 가능
→ 중요한 작업(사용자 입력) 먼저 처리

시간 →
[렌더링] [사용자 입력] [렌더링 재개] [렌더링 완료]

핵심 기능

1. startTransition - 우선순위 낮추기

import { startTransition, useState } from 'react';

function SearchPage() {
    const [input, setInput] = useState('');
    const [results, setResults] = useState([]);

    const handleChange = (e) => {
        // 긴급 업데이트 (높은 우선순위) - 입력값 즉시 반영
        setInput(e.target.value);

        // 급하지 않은 업데이트 (낮은 우선순위) - 나중에 처리
        startTransition(() => {
            setResults(searchItems(e.target.value));  // 무거운 작업
        });
    };

    return (
        <>
            <input value={input} onChange={handleChange} />
            <ResultList results={results} />
        </>
    );
}

2. useTransition - 로딩 상태 관리

import { useTransition } from 'react';

function TabContainer() {
    const [isPending, startTransition] = useTransition();
    const [tab, setTab] = useState('home');

    const handleTabChange = (nextTab) => {
        startTransition(() => {
            setTab(nextTab);  // 무거운 탭 전환 → 낮은 우선순위
        });
    };

    return (
        <>
            <TabButton onClick={() => handleTabChange('posts')}>Posts</TabButton>

            {/* 전환 중 로딩 표시 */}
            {isPending ? <Spinner /> : <TabContent tab={tab} />}
        </>
    );
}

3. useDeferredValue - 값 업데이트 지연

import { useDeferredValue } from 'react';

function SearchResults({ query }) {
    // query가 빠르게 바뀌어도 렌더링은 여유있게
    const deferredQuery = useDeferredValue(query);

    return (
        <>
            {/* 입력값은 즉시 반영 */}
            <p>검색어: {query}</p>

            {/* 결과는 여유있게 렌더링 */}
            <HeavyResultList query={deferredQuery} />
        </>
    );
}

4. Suspense - 로딩 선언적 처리

function App() {
    return (
        <Suspense fallback={<Spinner />}>
            {/* 데이터 로딩 중이면 Spinner 표시 */}
            <UserProfile />
        </Suspense>
    );
}

우선순위 개념

높은 우선순위 (긴급)     낮은 우선순위 (여유)
─────────────────        ─────────────────
사용자 입력              startTransition 내부 상태
클릭 이벤트             useDeferredValue
포커스                  데이터 패칭 결과 반영

React 18 활성화 방법

// React 17 이하 (동시성 모드 X)
ReactDOM.render(<App />, document.getElementById('root'));

// React 18 (동시성 모드 O)
ReactDOM.createRoot(document.getElementById('root'))
        .render(<App />);

언제 활용하나?

상황해결책
검색어 입력 시 결과 렌더링 버벅임startTransition
탭 전환 시 느린 렌더링useTransition
빠르게 바뀌는 값 기반 무거운 렌더링useDeferredValue
비동기 데이터 로딩 UISuspense

React 동시성 모드의 핵심은 "모든 렌더링이 동등하지 않다" 는 것입니다. 사용자 입력처럼 즉각 반응해야 할 것과, 검색 결과처럼 여유있게 처리해도 될 것을 우선순위로 구분해 UX를 개선합니다.

CSLOG에서 보기