본문 바로가기
Frontend2026년 4월 29일7분 읽기

React Compiler 1.0 정식 출시 — useMemo·useCallback 작별 가이드

YS
김영삼
조회 559
React Compiler 1.0 정식 출시 — useMemo·useCallback 작별 가이드

핵심 요약

React Compiler 1.0이 정식 stable 단계에 진입했다(React 19.2 기반). Meta Quest Store 등 대규모 프로덕션에서 검증됐고 초기 로드·페이지 전환 최대 12% 개선, 일부 인터랙션은 2.5배 빨라졌다. useMemo·useCallback·React.memo를 99% 안 써도 된다.

  • 빌드 타임 자동 메모이제이션
  • React Native에도 동일 적용
  • 코드 재작성 없이 도입
  • opt-in/opt-out 디렉티브 지원

1. 무엇을 자동화하는가

Before — 수동 메모이제이션

function ProductList({ products, filter }) {
  const filtered = useMemo(
    () => products.filter(p => p.category === filter),
    [products, filter]
  )
  const handleClick = useCallback(
    (id) => router.push('/product/' + id),
    [router]
  )
  return filtered.map(p => (
    <ProductCard key={p.id} product={p} onClick={handleClick} />
  ))
}
const ProductCard = memo(({ product, onClick }) => { ... })

After — 컴파일러가 자동으로

function ProductList({ products, filter }) {
  const filtered = products.filter(p => p.category === filter)
  const handleClick = (id) => router.push('/product/' + id)
  return filtered.map(p => (
    <ProductCard key={p.id} product={p} onClick={handleClick} />
  ))
}
function ProductCard({ product, onClick }) { ... }
// 같은 props면 자동 스킵

2. 설치 — Vite/Next.js

# 설치
npm i -D babel-plugin-react-compiler

# Next.js 16+
// next.config.js
module.exports = {
  experimental: { reactCompiler: true },
}

# Vite
// vite.config.ts
import react from '@vitejs/plugin-react'
export default {
  plugins: [react({
    babel: { plugins: ['babel-plugin-react-compiler'] }
  })],
}

3. eslint-plugin-react-compiler — 필수

컴파일러는 "Rules of React"를 어긴 코드에선 안전상 메모이제이션을 포기한다. ESLint 플러그인이 위반을 잡아준다.

npm i -D eslint-plugin-react-hooks@latest
// .eslintrc
{
  "extends": ["plugin:react-hooks/recommended-latest"]
}

흔한 위반 사례:

  • render 중 mutation (props.foo = bar)
  • render 중 ref 읽기 (ref.current)
  • conditional hook 호출

4. 점진적 도입 — opt-in 모드

// next.config.js — 특정 디렉터리만
experimental: {
  reactCompiler: {
    compilationMode: 'annotation',  // "use memo" 디렉티브 있는 파일만
  },
}
// app/products/page.tsx
'use memo'
export default function Products() { ... }  // 컴파일러 적용

역으로 특정 컴포넌트만 제외:

function LegacyComponent() {
  'use no memo'  // 컴파일러 비활성
  // ...
}

5. 실측 효과 (Meta Quest Store)

지표개선
초기 로드+12%
페이지 전환+12%
주요 인터랙션 (검색·필터)2.5x 빠름
메모리중립

6. 코드 사이즈 영향

컴파일러는 useMemoCache 호출을 추가해 약 5~15% 번들 사이즈 증가. 대신 직접 작성한 useMemo/useCallback을 모두 삭제하면 상쇄 또는 감소.

7. 안 되는 케이스

  • 비표준 JSX 변환기 사용 시 — 표준 React JSX만 지원
  • 매우 오래된 React — React 17 이상 필요(공식은 18.3+)
  • 외부 의존성의 비순수 함수 호출 — 컴파일러가 보수적으로 메모이제이션 포기

8. 마이그레이션 단계

  1. 1주차: ESLint 플러그인 추가 + 위반 수정
  2. 2주차: 컴파일러 도입(annotation 모드) — 1~2개 라우트만
  3. 3~4주차: React DevTools Profiler로 효과 측정
  4. 5주차+: 전체 모드(compilationMode: 'all')로 전환
  5. 이후: 기존 useMemo/useCallback 점진 제거 (선택)

9. 디버깅 팁

// React DevTools에서
// 1) Profiler → "Why did this render?" 활성화
// 2) 메모이제이션 적용된 컴포넌트는 "Memoized" 표시
// 3) 적용 안 된 곳은 ESLint 경고 메시지 확인

// 컴파일러가 무시한 컴포넌트 찾기
// babel.config.js
plugins: [['babel-plugin-react-compiler', {
  logger: { logEvent: (filename, event) => {
    if (event.kind === 'CompileSkipped') console.log(filename, event)
  }}
}]]

자주 묻는 질문

그럼 useMemo는 영영 안 써도 되나?

99%는 그렇다. 예외: (1) 매우 비싼 계산(이미지 처리·암호화)에 명시적 의존성 표현이 가독성에 도움될 때, (2) 컴파일러가 메모이제이션을 포기한 곳을 ESLint로 확인하고 보강.

React Native도 적용되나?

예. 0.78+ 권장. 동일 패키지(babel-plugin-react-compiler)로 적용.

Server Components와도 호환?

예. 컴파일러는 클라이언트 컴포넌트만 처리. 서버 컴포넌트는 영향 없음.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록