← 목록으로

React Activity 컴포넌트, 성능 개선기

2026-06-09

조건부 렌더링의 성능 이슈

조건부 렌더링을 구현할 때 흔히 아래와 같이 작성한다.

import { useState, Suspense } from "react";

export default function Toggle() {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div>
      <button onClick={() => setIsVisible((prev) => !prev)}>
        {isVisible ? "숨기기" : "보이기"}
      </button>
      {isVisible && (
        <Suspense fallback={<p>로딩중 ...</p>}>
          <UserFetch />
        </Suspense>
      )}
    </div>
  );
}

function UserFetch() {
  const { data } = useSuspenseQuery({
    queryKey: ["user"],
    queryFn: fetchData,
  });

  return (
    <div>
      <p>user: {data.user}</p>
      <p>name: {data.name}</p>
    </div>
  );
}

UserFetch 내부에는 서버로부터 데이터를 받아오는 fetching 로직이 있다. 위 코드처럼 작성하면 컴포넌트가 보여지는 시점에 데이터 fetching이 시작되기 때문에, 사용자는 버튼을 누를 때 로딩 대기 시간을 겪게 된다.


React 19의 Activity 컴포넌트

React 19에서 출시된 Activity 컴포넌트를 사용하면 이 문제를 해결할 수 있다.

import { useState, Activity, Suspense } from "react";

export default function Toggle() {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div>
      <button onClick={() => setIsVisible((prev) => !prev)}>
        {isVisible ? "숨기기" : "보이기"}
      </button>
      <Activity mode={isVisible ? "visible" : "hidden"}>
        <Suspense fallback={<p>로딩중 ...</p>}>
          <UserFetch />
        </Suspense>
      </Activity>
    </div>
  );
}

Activitymode prop으로 "visible" / "hidden" 을 받는다. "hidden" 상태일 때도 컴포넌트를 언마운트하지 않고 백그라운드에서 렌더링을 유지한다. 덕분에 UserFetch의 데이터 fetching이 사전에 완료되어, 사용자가 버튼을 눌렀을 때 로딩 없이 즉시 컨텐츠가 노출된다.


복잡한 페이지에서의 렌더링 우선순위 제어

Activity는 조건부 렌더링 외에도, 복잡한 페이지에서 렌더링 우선순위를 조절하는 데에도 활용할 수 있다.

네이버 화면에서 예를들어보면, 보라색 박스친 부분이 중요도가 낮게 설정된 영역이라 가정한다면,

네이버 메인 페이지 예시

해당 영역을 Activity로 감싸, 메인 컨텐츠의 렌더링을 먼저 완료한 뒤 나중에 렌더링하도록 미룰 수 있다.

export default function Home() {
  return (
    <div>
      {/* 중요한 메인 컨텐츠 */}
      <MainContent />
      {/* 낮은 우선순위 컴포넌트 */}
      <Activity>
        <NotImportantComponent />
      </Activity>
    </div>
  );
}

Performance 탭에서 실제 동작 차이 비교

Next.js의 Performance 탭에서 실제 동작 차이를 확인하면 다음과 같다.

케이스동작
Activity 미적용하이드레이션 과정 중에 NotImportantComponent가 렌더링됨
Activity 적용하이드레이션 완료 후 idle 상태에서 NotImportantComponent가 렌더링됨

Activity 미적용 Activity 미적용 Performance 탭

Activity 적용 Activity 적용 Performance 탭

Activity를 적용하면 중요하지 않은 컴포넌트의 렌더링이 브라우저의 유휴 시간으로 밀려나, 메인 컨텐츠의 하이드레이션 성능이 개선된다.


정리

장점

단점

향후 React에서 출시 예정인 ViewTransition 컴포넌트와 조합하면 부드러운 전환 효과도 함께 구현할 수 있을 것으로 기대된다.