동시성 렌더링 (Concurrent Rendering)

강연주·2024년 12월 30일

📚 TIL

목록 보기
122/186

Concurrent Rendering이란?

Concurrent Rendering은 React 18에서 도입된 새로운 렌더링 메커니즘으로,
React가 여러 버전의 UI를 동시에 준비하고 중요도에 따라 렌더링을 조절할 수 있게 하는 기능이다.


특징

  • 렌더링 중단 가능
    : 더 중요한 업데이트가 발생하면 진행 중인 렌더링을 중단하고 새로운 업데이트를 처리할 수 있다.

  • 우선순위 기반 렌더링
    : 다양한 UI 업데이트에 우선순위를 부여할 수 있다.

  • 렌더링 일시 중지
    : 사용자 경험을 위해 렌더링을 일시적으로 중지할 수 있다.


예시

1. useTransition 활용

🖥️ jsx

import { useState, useTransition } from 'react';

function SearchResults() {
  const [query, setQuery] = useState('');
  const [isPending, startTransition] = useTransition();
  
  const handleChange = (e) => {
    // 입력값 업데이트는 긴급 업데이트 (높은 우선순위)
    setQuery(e.target.value);
    
    // 검색 결과 업데이트는 non-urgent 업데이트 (낮은 우선순위)
    startTransition(() => {
      // 무거운 필터링 작업
      setFilteredResults(heavyComputation(e.target.value));
    });
  };

  return (
    <div>
      <input value={query} onChange={handleChange} />
      {isPending ? (
        <div>검색 결과 업데이트 중...</div>
      ) : (
        <SearchResultsList results={filteredResults} />
      )}
    </div>
  );
}
  • 입력값 업데이트는 즉시 반영됨 (높은 우선순위)
  • 검색 결과 계산은 백그라운드에서 처리됨 (낮은 우선순위)
  • 사용자는 입력 도중에도 UI가 멈추지 않는 것을 경험

2. Suspense와 함께 사용

🖥️ jsx

import { Suspense, useState, useTransition } from 'react';

function ProfilePage() {
  const [selectedTab, setSelectedTab] = useState('posts');
  const [isPending, startTransition] = useTransition();

  function selectTab(tab) {
    startTransition(() => {
      setSelectedTab(tab);
    });
  }

  return (
    <div>
      <TabButton 
        isActive={selectedTab === 'posts'}
        onClick={() => selectTab('posts')}
      >
        게시물
      </TabButton>
      <TabButton 
        isActive={selectedTab === 'photos'}
        onClick={() => selectTab('photos')}
      >
        사진
      </TabButton>
      
      {/* 탭 전환 시 깜빡임 방지 */}
      <div style={{ opacity: isPending ? 0.8 : 1 }}>
        <Suspense fallback={<Spinner />}>
          {selectedTab === 'posts' ? <Posts /> : <Photos />}
        </Suspense>
      </div>
    </div>
  );
}
  • 탭 전환을 non-urgent 업데이트로 처리
  • 전환 중에는 기존 콘텐츠를 흐리게 표시
  • Suspense로 새로운 콘텐츠 로딩 상태 처리

3. Concurrent Features의 실제 이점

🖥️ jsx

import { useDeferredValue } from 'react';

function SlowList({ text }) {
  const deferredText = useDeferredValue(text);
  
  return (
    <div>
      {/* 무거운 리스트 렌더링 */}
      {createExpensiveList(deferredText)}
    </div>
  );
}

function App() {
  const [text, setText] = useState('');
  
  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <SlowList text={text} />
    </>
  );
}

useDeferredValue를 사용 시

  • 입력에 대한 즉각적인 반응을 유지하면서
  • 무거운 리스트 업데이트는 지연시켜 처리
  • 불필요한 중간 상태 렌더링을 건너뛸 수 있음

defer
verb
past tense: deferred; past participle: deferred
put off (an action or event) to a later time; postpone.
"they deferred the decision until February"


➡️ 이러한 Concurrent Rendering의 특징들은 특히 대규모 리스트 렌더링,
복잡한 데이터 시각화, 실시간 검색 기능, 탭 전환과 같은 복잡한 UI 전환
에서 매우 효과적으로 활용될 수 있다.

profile
아무튼, 개발자

0개의 댓글