본문 바로가기
C.W.K.
Stream
Lesson 04 of 06 · published

React Compiler의 자동 메모이제이션

~13 min · react-compiler, memoization, build

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
React Compiler는 코드에서 안전한 메모이제이션 지점을 찾아 자동으로 적용해. 습관적으로 useMemo와 useCallback을 뿌리던 방식을 다시 생각해 보자.

빌드할 때 안전한 캐시 경계를 찾아

React Compiler는 JSX와 값의 사용 관계를 분석하는 빌드 플러그인이야. 다시 계산할 필요가 없는 값과 안정적으로 유지할 수 있는 콜백을 찾아 useMemo와 useCallback에 해당하는 최적화를 생성해. 작성자는 자연스러운 컴포넌트 코드를 유지할 수 있어.

컴포넌트의 의미는 바꾸지 않아

Compiler는 useState, useEffect, useContext를 대신하지 않아. 상태와 부수 효과의 계약은 그대로야. 아주 비싼 계산 자체를 없애지도 않으므로 query가 바뀔 때마다 큰 데이터를 거르는 작업은 여전히 실행될 수 있어. 그런 체감 성능 문제에는 useTransition이나 useDeferredValue가 함께 필요할 수 있어.

Vite 빌드에 연결해

babel-plugin-react-compiler를 설치하고 @vitejs/plugin-react의 Babel plugin 목록에 추가해. 개발 서버를 다시 시작한 뒤 빌드 로그와 DevTools Profiler로 실제 적용 여부를 확인해.

예외는 좁게 표시해

외부에서 관찰되는 참조 동일성 때문에 최적화를 적용하면 안 되는 드문 컴포넌트에는 'use no memo' 지시어를 둘 수 있어. 여러 곳에서 반복된다면 지시어보다 설계를 먼저 의심해.

측정 근거 없이 방어적인 memo를 늘리지 마. 자연스러운 코드를 작성하고 Compiler와 Profiler가 보여 주는 실제 병목만 따로 고쳐.

Compiler와 ESLint를 함께 사용해

eslint-plugin-react-compiler는 prop을 수정하거나 렌더링 중 값을 불안정하게 바꾸는 등 안전한 최적화를 막는 패턴을 알려 줘. 경고를 무조건 끄기보다 컴포넌트가 React의 순수성 계약을 어기는지 확인해.

Compiler가 켜졌는지는 package 설치만으로 판단하지 마. Vite의 React plugin에 Babel plugin이 실제로 등록됐는지, 개발 서버를 재시작했는지, 빌드 결과와 Profiler에서 다시 렌더링이 줄었는지 확인해.

Code

vite.config.ts: React Compiler 활성화·ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: [
          // npm i -D babel-plugin-react-compiler
          ["babel-plugin-react-compiler", { /* 필요 시 옵션 */ }],
        ],
      },
    }),
    tailwindcss(),
  ],
});
변경 전과 후: 직접 쓴 것 vs 도는 것·tsx
// 본인이 쓰는 것 (깔끔, 자연)
function Greeting({ name, tags }: { name: string; tags: string[] }) {
  const full = `Hello, ${name}!`;
  const sortedTags = [...tags].sort();
  const onClick = () => console.log(name);
  return (
    <div>
      <h1>{full}</h1>
      <TagList tags={sortedTags} onItemClick={onClick} />
    </div>
  );
}

// Compiler가 생성하는 코드 (개념적) — 효과가 있는 부분을 메모이제이션해
function Greeting({ name, tags }: { name: string; tags: string[] }) {
  const full = $useMemo(() => `Hello, ${name}!`, [name]);
  const sortedTags = $useMemo(() => [...tags].sort(), [tags]);
  const onClick = $useCallback(() => console.log(name), [name]);
  return (
    <div>
      <h1>{full}</h1>
      <TagList tags={sortedTags} onItemClick={onClick} />
    </div>
  );
}

// 위 코드는 작성자가 쓰고 아래 코드는 Compiler가 생성해. 아래 코드는 name과 tags가 바뀌지 않는
// 동안 정렬된 배열과 콜백을 다시 만들지 않아..

External links

Exercise

Vite 프로젝트에 React Compiler Babel plugin을 연결하고 개발 서버를 다시 시작해. useMemo와 useCallback이 있는 컴포넌트 하나를 골라 수동 래퍼를 제거한 뒤 동작이 같은지 확인해. 변경 전후를 Profiler의 같은 상호작용으로 측정하고 다시 렌더링 횟수와 commit 시간을 기록해. 차이가 난다면 plugin이 실제 빌드에 들어갔는지 log와 출력에서 확인해.
Hint
Package 설치만으로 활성화를 판단하지 마. Vite 설정, 개발 서버 재시작, build 결과, Profiler의 네 증거를 확인하고 의도적으로 만든 Compiler lint 경고도 하나 고쳐 봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.