React Compiler는 ‘memo 삭제 버튼’이 아니라 렌더링 계약 검사기다
React Compiler를 켜기 전에 우리 코드가 “컴파일러가 안전하게 최적화할 수 있는 렌더링 계약”을 지키는지 어떻게 확인할까?
React Compiler는 ‘memo 삭제 버튼’이 아니라 렌더링 계약 검사기다
- 카테고리: web_app_dev
- 예상 읽기 시간: 10분
- 오늘의 질문: React Compiler를 켜기 전에 우리 코드가 “컴파일러가 안전하게 최적화할 수 있는 렌더링 계약”을 지키는지 어떻게 확인할까?
- 핵심 출처:
- React Compiler v1.0 - 2025-10-07 게시, 2026-06-17 확인
- Introduction – React Compiler - 게시일 미표기, 2026-06-17 확인
- Incremental Adoption – React Compiler - 게시일 미표기, 2026-06-17 확인
- Installation – React Compiler - 게시일 미표기, 2026-06-17 확인
- Next.js 16 - 게시일 미표기, 2026-06-17 확인
1. 왜 지금 봐야 하나
React Compiler 1.0이 안정 릴리스가 되었고, Next.js 16도 React Compiler 지원을 stable로 소개한다. 표면적으로는 “이제 useMemo, useCallback, React.memo를 덜 써도 된다”는 이야기처럼 들린다. 하지만 웹앱 팀이 바로 받아들여야 할 메시지는 조금 다르다.
React Compiler는 런타임 마법이 아니라 빌드 타임 최적화 도구다. 컴포넌트와 훅의 데이터 흐름, 변경 가능성, Rules of React 위반 여부를 분석해서 안전하다고 판단되는 곳에 자동 메모이제이션을 넣는다. 그래서 컴파일러 도입은 성능 옵션 하나를 켜는 일이 아니라, 우리 렌더링 코드가 분석 가능한 형태인지 확인하는 일에 가깝다.
이 차이를 놓치면 두 가지 실패가 생긴다.
- 컴파일러가 많은 컴포넌트를 조용히 건너뛰는데도 “켜놨으니 빨라졌겠지”라고 믿는다.
- 기존 수동 메모이제이션을 한 번에 지우다가 실제 병목과 의도적 안정성 경계를 잃어버린다.
오늘의 관점은 React Compiler를 “성능 자동화”가 아니라 렌더링 계약 검사기 + 점진적 최적화 레이어로 보는 것이다.
2. 핵심 개념
React Compiler가 최적화하려는 대상은 주로 “기존 화면의 업데이트 성능”이다. 즉 첫 로딩을 무조건 빠르게 해주는 도구라기보다, state·props·context 변화가 있을 때 불필요한 하위 렌더링과 비싼 계산을 줄이는 도구다.
React 문서가 강조하는 핵심은 다음 세 가지다.
- 컴파일러는 plain JavaScript와 React 코드의 데이터 흐름을 분석한다.
- 안전하다고 판단되는 컴포넌트와 훅에 자동 메모이제이션을 적용한다.
- Rules of React를 어기는 코드나 분석하기 어려운 패턴은 최적화하지 않고 건너뛸 수 있다.
여기서 중요한 단어는 “자동”보다 “안전하다고 판단되는”이다. 컴파일러는 모든 렌더링 문제를 고쳐주는 것이 아니다. 예를 들어 렌더 중 외부 상태를 변경하거나, 훅 규칙을 어기거나, 컴포넌트가 props를 불변 값처럼 다루지 않는다면 컴파일러가 최적화할 수 있는 표면이 줄어든다.
따라서 React Compiler 시대의 좋은 React 코드는 “메모를 많이 쓴 코드”가 아니라 “렌더 함수가 입력에 대해 예측 가능하고, 변경 가능한 값의 경계가 분명한 코드”다.
3. 최신 이슈와 연결
React 팀은 2025년 10월 React Compiler v1.0을 발표하면서 안정 릴리스, eslint-plugin-react-hooks의 compiler-powered lint rules, 점진적 도입 가이드를 함께 공개했다. React Compiler는 React와 React Native 모두에서 동작하며, optional chain과 array index 의존성 처리 같은 개선도 포함한다.
Next.js 16은 React Compiler 지원을 stable로 올렸다. 다만 Next.js 블로그는 reactCompiler 설정이 기본 활성화는 아니며, Babel 기반이기 때문에 개발·빌드 시간이 증가할 수 있다고 설명한다. 즉 프레임워크가 지원한다고 해서 모든 프로젝트가 즉시 전면 도입해야 한다는 뜻은 아니다.
React 설치 문서도 같은 방향을 말한다. React Compiler는 Babel 플러그인으로 들어가며, 원본 소스 정보를 분석해야 하므로 Babel 플러그인 파이프라인에서 먼저 실행되어야 한다. ESLint 통합은 컴파일러가 최적화할 수 없는 컴포넌트나 훅을 알려준다. 이 lint 결과는 “빌드 실패”보다 “최적화 커버리지 지도”에 가깝다.
즉 최신 변화의 핵심은 다음이다.
React 성능 튜닝이 개별
useMemo감각에서, 컴파일러가 이해할 수 있는 코드 건강도와 점진적 rollout 전략으로 이동하고 있다.
4. 개발자 관점 해석
실무에서 React Compiler를 도입할 때 제일 위험한 문장은 “이제 memo 다 지워도 되겠네”다. 더 나은 문장은 “수동 메모이제이션을 줄이되, 렌더링 계약을 더 엄격히 보자”다.
수동 메모이제이션은 왜 줄어들 수 있나
수동 useMemo와 useCallback은 종종 의존성 배열을 잘못 적거나, inline function 때문에 기대한 효과가 깨지거나, 실제 병목이 아닌 곳에 유지보수 비용을 만든다. React Compiler는 이런 반복적인 최적화 코드를 빌드 단계에서 더 세밀하게 넣을 수 있다.
그래도 사람이 봐야 하는 것은 무엇인가
컴파일러는 제품 의도를 모른다. 다음은 여전히 개발자가 결정해야 한다.
- 비싼 계산을 렌더 중에 둘 것인가, 서버·worker·캐시로 옮길 것인가
- prop identity가 API 계약인지, 우연히 안정적이었는지
- 특정 컴포넌트의 재렌더 방지가 UX 품질에 실제로 의미 있는지
- gating이나 annotation 모드로 어느 사용자·어느 디렉터리부터 켤 것인지
- 컴파일러 적용 후 빌드 시간 증가를 감당할 수 있는지
실패 모드
- 무측정 도입: React DevTools Profiler나 사용자 체감 지표 없이 “빌드가 되니 성공”으로 판단한다.
- 전면 활성화 후 원인 추적 불가: 어떤 디렉터리에서 성능이 좋아졌거나 깨졌는지 구분하지 못한다.
- lint를 에러 목록으로만 취급: lint 위반을 모두 즉시 고치려다 마이그레이션이 멈춘다. 실제로는 “어디가 최적화에서 빠지는지”를 보는 지도로 써야 한다.
- 수동 memo 일괄 삭제: 의도적으로 안정적인 callback identity를 제공하던 public component나 라이브러리 경계를 망가뜨릴 수 있다.
5. 내 프로젝트에 적용할 체크포인트
React Compiler를 켜기 전, 다음 질문에 답해보자.
- 우리 앱의 실제 렌더링 병목 화면은 어디인가? 목록, 대시보드, 에디터, 채팅, 폼 중 무엇인가?
- 해당 화면에서 state 변경 시 함께 리렌더되는 컴포넌트 트리를 알고 있는가?
eslint-plugin-react-hooks최신 preset을 적용했는가?- lint 결과를 “컴파일러가 건너뛸 컴포넌트 목록”으로 볼 수 있게 CI나 리포트에 남기는가?
- Next.js라면
reactCompiler를 전면 활성화하기 전에 빌드 시간 변화를 측정했는가? - Vite/Babel/Metro라면 React Compiler 플러그인이 다른 Babel 변환보다 먼저 실행되는가?
- legacy 영역과 신규 영역을 분리해 디렉터리 단위 도입이 가능한가?
"use memo"annotation 모드나 runtime gating을 쓸 이유가 있는가?- 기존
useMemo/useCallback을 삭제할 때 “성능 최적화용”과 “API identity 계약용”을 구분했는가?
작은 팀이라면 처음부터 전면 도입하지 말고, 렌더 병목이 분명한 화면 하나를 고르는 편이 낫다. 예를 들어 “검색 결과 200개가 필터 변경 때마다 흔들리는 화면”처럼 재현 가능한 시나리오가 좋다.
6. 오늘 10분 액션
오늘 10분 동안 할 일은 “React Compiler를 켜기”가 아니라 “켤 수 있는 표면을 확인하기”다.
- 프로젝트에서 렌더링이 무겁다고 느끼는 화면 하나를 고른다.
- 그 화면의 상위 컴포넌트와 주요 하위 컴포넌트 파일을 적는다.
- 최신
eslint-plugin-react-hooks설정을 확인하고, compiler 관련 lint가 켜질 수 있는지 본다. - React DevTools Profiler로 현재 상호작용 하나를 기록한다. 예: 필터 변경, 탭 전환, 입력 타이핑.
- 결과를 한 줄로 적는다.
예시 메모:
화면: /dashboard/orders
상호작용: 상태 필터 변경
현재 문제: OrderTableRow 200개가 함께 리렌더됨
Compiler 도입 후보: src/features/orders/**
주의: useOrderSelection hook은 외부 store와 연결되어 있어 먼저 lint 확인 필요
이 메모가 있으면 React Compiler 도입은 추상적인 “성능 개선”이 아니라 측정 가능한 실험이 된다.
7. 더 볼 자료
- React Compiler v1.0 릴리스 글: 안정화 배경, 자동 메모이제이션의 범위, ESLint 통합을 확인한다.
- React Compiler Introduction: 어떤 렌더링 비용을 줄이는지, 무엇을 자동화하지 않는지 먼저 읽는다.
- Incremental Adoption 문서: Babel overrides,
"use memo", runtime gating으로 점진 도입하는 방법을 본다. - Installation 문서: Babel/Vite/Next.js/React Native 설정과 ESLint 통합을 확인한다.
- Next.js 16 릴리스 글: Next.js에서 React Compiler stable 지원과 빌드 시간 tradeoff를 확인한다.
중복 회피 메모
최근 web_app_dev 글은 Next.js Cache Components의 데이터 신선도 계약, Supabase AI 에이전트 권한표, Supabase Auth/RLS/Realtime, Hono 보안 릴리스, Node TypeScript 실행 계약, Next.js AI 디버깅을 다뤘다. 이번 글은 Next.js 캐시나 AI 디버깅을 반복하지 않고, React Compiler 1.0과 Next.js 16의 stable 지원을 바탕으로 자동 메모이제이션을 렌더링 계약, lint 기반 최적화 커버리지, 점진적 rollout 전략으로 해석하는 데 집중한다.
핵심 출처
로그인하면 이 글을 북마크하고, 나만 보는 한 줄 메모를 남길 수 있어요.
댓글 0
최신순 ▾혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)