기존 React의 렌더링 방식은 동기적(Synchronous)이었습니다. 한 번 렌더링이 시작되면 중단할 수 없었기 때문에, 데이터가 많거나 복잡한 연산이 필요한 컴포넌트를 렌더링할 때 브라우저의 메인 스레드가 차단(Blocking)되는 현상이 발생했습니다.
React 18은 이러한 문제를 해결하기 위해 동시성(Concurrency) 메커니즘을 도입했습니다. 핵심은 "렌더링의 우선순위를 정하고 중단 및 재개할 수 있게 만드는 것"입니다. 이를 위해 다음과 같은 기능들이 추가되었습니다.
React 18 이전의 렌더링은 선형적이었으나, 18부터는 여러 작업을 동시에 준비하고 우선순위가 높은 작업을 먼저 처리합니다.
입력값은 즉시 업데이트하되, 그로 인해 발생하는 무거운 리스트 필터링은 비긴급으로 처리합니다.
import { useState, useTransition } from 'react'; function SearchComponent() { const [isPending, startTransition] = useTransition(); const [query, setQuery] = useState(''); const [list, setList] = useState<string[]>([]); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { // 1. 긴급 업데이트: 입력창 반응 setQuery(e.target.value); // 2. 비긴급 업데이트: 무거운 작업 지연 처리 startTransition(() => { const filtered = heavyFilterTask(e.target.value); setList(filtered); }); }; return ( <div> <input type="text" onChange={handleChange} value={query} /> {isPending ? <p>업데이트 중...</p> : <List items={list} />} </div> ); }
서버와 클라이언트 사이의 ID 불일치(Hydration Mismatch) 문제를 해결합니다.
function FormField() { const id = useId(); return ( <div> <label htmlFor={id}>이메일</label> <input id={id} type="email" /> </div> ); }
useTransition, useDeferredValue) 코드 구조가 복잡해질 수 있습니다.React 18은 단순한 버전 업을 넘어 렌더링 패러다임의 거대한 전환을 보여줍니다. 특히 Suspense와 동시성 모델은 앞으로의 React 생태계(Next.js App Router 등)의 근간이 되므로 반드시 숙지해야 할 개념입니다.
참고 자료: