이번 시간에는 React의
Concurrent mode와Suspense에 대해서 알아보는 시간을 갖도록 하겠습니다.
동시성(Concurrency)은 여러 작업이 동일한 시간 간격 내에서 서로 번갈아가며 실행되는 특성을 의미한다. 꼭 작업들이 동시에 실행되는 것은 아니며, 작은 단위로 작업들을 쪼개서 빠르게 전환하면서 실행되는 방식을 포함한다.
자바스크립트는 싱글 스레드(Single-threaded) 기반 언어로, 한 번에 하나의 작업만 실행할 수 있다. 그러나, 우리들이 알고 있듯이 자바스크립트는 작업을 나누어 비동기로 처리하여 마치 동시에 작업들이 실행되는 것처럼 흉내낸다.
=> 동시에 실행되는 것처럼 보이지만, 실제로는 작은 작업 단위를 빠르게 전환하면서 실행

UI 업데이트의 우선순위를 더 잘 관리하고 보다 부드러운 사용자 경험을 제공하기 위한 방식이다. 기존 React 렌더링 방식인 동기식(Synchronous) 렌더링과 비교했을 때, Concurrent Mode는 비동기적으로 렌더링을 수행하여 더 복잡한 UI 요구사항을 효과적으로 처리할 수 있도록 한다.
이전의 React는 기본적으로 단일 스레드에서 동작하며, 렌더링 작업이 크거나 복잡해지면 메인 스레드를 장시간 점유하게 된다.
=> 화면이 멈추거나(lagging), 사용자 인터랙션이 지연되는 문제가 발생.
사용자가 UI와 상호작용(스크롤, 클릭 등)할 때, React의 동기적 렌더링 모델에서는 이미 진행 중인 작업이 완료될 때까지 새 작업을 처리하지 못한다.
=> 사용자 입장에서인터페이스가 "버벅거리는" 현상을 초래하며, 사용자 경험을 저하시키는 문제가 발생.
사용자 인터페이스에서 높은 우선순위를 가진 작업(예: 클릭, 입력)이 생길 때, 기존 작업을 중단하고 높은 우선순위의 작업을 처리할 수 있는 유연성이 요구되기 시작.
동시성을 통해 사용자 경험을 향상시키고, 대규모 애플리케이션에서도 성능과 유연성을 극대화하기 위해
Concurrent Mode가 등장
1. 작업 우선순위 관리
사용자의 입력(클릭, 스크롤 등)과 같은 긴급한 작업을 고우선으로 처리하고, 긴급하지 않은 작업은 나중으로 미룬다. 렌더링 작업을 중단했다가 다시 시작할 수 있는 "interruptible rendering"을 지원.
2.시간 분할(Time Slicing)
작업을 작은 조각으로 나누어 일정 시간 동안 실행한 후 나머지를 대기시킴으로써, 메인 스레드를 독점하지 않고 다른 작업을 수행할 수 있는 여유를 남긴다. 이로 인해 UI가 더 부드럽게 반응하도록 한다.
3. 유연한 렌더링 중단 및 재개
화면 업데이트 중 사용자의 입력이 발생하면, React는 현재 진행 중인 작업을 중단하고 사용자 상호작용을 먼저 처리한 후, 중단된 작업을 이어서 진행.
4. Suspense와의 통합
Suspense와 함께 작동하여 비동기 데이터 로딩과 같은 작업이 포함된 UI를 매끄럽게 렌더링한다.
=> 네트워크 요청 결과가 로드되기 전에 로딩 상태를 표시하는 등의 기능을 쉽게 구현할 수 있다.
ReactDOM.createRoot()를 사용하여 Concurrent Mode 활성화
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
// Concurrent Mode 활성화
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
Suspense는 아직 렌더링이 준비되지 않은 컴포넌트가 있을 때 로딩 화면을 보여주고, 로딩이 완료되면 렌더링이 준비된 컴포넌트를 보여주는 기능이다. 이를fallback UI를 제공한다고 한다.
=> UI를 비동기 데이터 로딩과 연결하여 매끄럽게 관리할 수 있게 해주는 기능
Suspense가 동작하려면 React 18 이상에서 ReactDOM.createRoot()를 사용해야 한다.
1. Suspense는 Concurrent Mode의 일부로 설계
Suspense는 Concurrent Mode에서 제공하는 비동기 렌더링 능력을 기반으로 동작한다.
데이터가 준비되지 않은 상태에서 렌더링을 일시적으로 중단하거나, 다른 작업을 먼저 처리하는 Concurrent Mode의 특성을 활용.
2. 비동기 렌더링 지원
Suspense는 데이터가 준비될 때까지 UI 업데이트를 지연시키는 역할을 하는데,
Concurrent Mode가 활성화된 환경에서는 데이터 로딩 동안 UI를 비동기적으로 처리하여 부드럽게 동작하게 만든다.
3. 로딩 상태 처리
Suspense는 데이터 로딩 중에 fallback UI를 표시하며, Concurrent Mode는 이러한 작업이 다른 렌더링 작업과 충돌하지 않도록 조율한다.
예를 들어, 네트워크 지연이 있는 경우에도 다른 UI 작업은 계속 진행될 수 있다.
4. 자원 관리 최적화
Concurrent Mode는 작업 우선순위를 관리하여 Suspense에서 발생하는 데이터 로딩 작업을 저우선으로 처리하고, 중요한 사용자 상호작용을 우선 처리할 수 있도록 돕는다.
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./MyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
예: 리스트 데이터를 서버에서 로드하는 동안, 다른 UI는 사용자가 계속 상호작용할 수 있도록 유지.
예: 페이지 전환 시, 새 데이터를 로드하는 동안 로딩 화면을 표시하면서도 이전 UI가 중단되지 않음.
예: 느린 네트워크 환경에서도 화면 깜박임 없이 필요한 데이터를 준비하고 렌더링.
Suspense는Concurrent Mode를 활용하여 비동기 작업(데이터 로딩, 코드 스플리팅 등)과 UI 렌더링을 매끄럽게 처리한다.
Concurrent Mode는Suspense가 비동기 상태를 효과적으로 관리할 수 있도록 우선순위 조정과 렌더링 작업 분할을 지원한다.
두 기능은 결합하여 사용자 경험을 개선하고, 대규모 애플리케이션에서도 성능을 극대화하는 데 기여합니다.