React 18 베타에서 Concurrent Rendering 테스트해보기

배경

관리자 페이지에서 5000개 이상의 상품 리스트를 렌더링할 때 검색 입력이 버벅이는 문제가 있었다. 디바운싱을 적용했지만 입력 자체가 느린 느낌은 여전했다.

React 18 베타에서 Concurrent Rendering 기능이 공개되어 테스트 환경에 적용해봤다.

기존 코드

function ProductList() {
  const [keyword, setKeyword] = useState('');
  const filtered = products.filter(p => 
    p.name.toLowerCase().includes(keyword.toLowerCase())
  );

  return (
    <>
      <input 
        value={keyword} 
        onChange={e => setKeyword(e.target.value)} 
      />
      <ul>
        {filtered.map(product => (
          <ProductItem key={product.id} product={product} />
        ))}
      </ul>
    </>
  );
}

입력과 렌더링이 동기적으로 처리되어 입력이 블로킹됐다.

useTransition 적용

import { useState, useTransition } from 'react';

function ProductList() {
  const [keyword, setKeyword] = useState('');
  const [deferredKeyword, setDeferredKeyword] = useState('');
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    setKeyword(e.target.value);
    startTransition(() => {
      setDeferredKeyword(e.target.value);
    });
  };

  const filtered = products.filter(p => 
    p.name.toLowerCase().includes(deferredKeyword.toLowerCase())
  );

  return (
    <>
      <input value={keyword} onChange={handleChange} />
      {isPending && <span>검색 중...</span>}
      <ul style={{ opacity: isPending ? 0.6 : 1 }}>
        {filtered.map(product => (
          <ProductItem key={product.id} product={product} />
        ))}
      </ul>
    </>
  );
}

입력은 즉시 반영되고, 리스트 렌더링은 낮은 우선순위로 처리되어 타이핑이 부드러워졌다.

결과

  • 입력 응답성이 체감상 확실히 개선됐다
  • isPending을 활용해 로딩 상태를 자연스럽게 표현할 수 있었다
  • 아직 베타라 프로덕션 적용은 보류했지만, 정식 출시되면 도입할 예정이다

React 18의 Concurrent 기능들이 기존 성능 문제를 더 선언적으로 해결할 수 있게 해줄 것 같다.

React 18 베타에서 Concurrent Rendering 테스트해보기