[🌙 아티클]
[핵심 요약] React Compiler(빌드 타임에 메모이제이션을 자동으로 넣어주는 컴파일러)가 안정화되면서 useMemo·useCallback·React.memo를 손으로 다는 시대가 저물고 있다. 컴파일러가 "어디를 메모할지"를 사람보다 정밀하게 판단한다. 다만 이건 마법이 아니라 Rules of React를 지킨 코드일 때만 동작한다.
무슨 일이 일어났나
그동안 React 성능 최적화의 기본기는 손으로 메모이제이션(이전 계산 결과를 캐싱해 불필요한 재계산·재렌더를 막는 것)을 거는 일이었다.
useMemo로 비싼 계산을 캐싱하고, useCallback으로 함수 참조를 고정하고, React.memo로 자식 컴포넌트의 재렌더를 막는 패턴 말이다.
그런데 React 공식 문서는 이제 입장을 바꿨다. 새 코드라면 이 훅들을 직접 달지 말고 React Compiler에 맡기라고 권한다. State of JavaScript 2025 설문에서도 컴파일러 도입이 빠르게 늘었다는 신호가 잡힌다.
기술적으로 어떤 의미인가
React Compiler는 런타임 라이브러리가 아니라 빌드 타임 도구다. 코드를 갈아엎지 않아도, 컴파일러가 컴포넌트와 훅을 분석해 두 가지를 자동으로 처리한다.
첫째, 부모 state가 바뀔 때 영향 없는 자식의 연쇄 재렌더(cascading re-render)를 끊는다. 둘째, 컴포넌트 안의 비싼 계산을 알아서 메모한다.
핵심은 "정밀함"이다. 사람이 의존성 배열을 잘못 적어 생기는 버그가 사라지고, 메모 범위도 보통 손으로 짠 것만큼, 혹은 더 잘게 잡힌다.
코드로 보면
공식 문서의 before/after를 보면 차이가 한눈에 들어온다.
// Before — 손으로 메모를 다 달던 시절
import { useMemo, useCallback, memo } from 'react';
const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) {
const processedData = useMemo(() => {
return expensiveProcessing(data);
}, [data]);
const handleClick = useCallback((item) => {
onClick(item.id);
}, [onClick]);
return (
<div>
{processedData.map(item => (
<Item key={item.id} onClick={() => handleClick(item)} />
))}
</div>
);
});
// After — 컴파일러가 알아서 메모. 로직만 남는다
function ExpensiveComponent({ data, onClick }) {
const processedData = expensiveProcessing(data);
const handleClick = (item) => {
onClick(item.id);
};
return (
<div>
{processedData.map(item => (
<Item key={item.id} onClick={() => handleClick(item)} />
))}
</div>
);
}
memo 래퍼, useMemo, useCallback이 통째로 사라졌다. 그런데도 최적화 효과는 같거나 더 낫다는 게 공식 설명이다.
내 코드에 어떻게 적용할까
첫째, 새 코드부터 적용한다. 신규 컴포넌트는 메모 훅 없이 깔끔하게 쓰고 컴파일러를 켠다.
둘째, 기존 코드는 성급히 걷어내지 말자. 이미 달려 있는 useMemo·useCallback은 escape hatch(컴파일러가 못 잡는 세밀한 제어용 탈출구)로 여전히 유효하다. 특히 useEffect 의존성에 쓰이는 메모는 함부로 지우면 동작이 바뀐다.
셋째, 전제는 Rules of React다. 컴파일러는 순수 함수 규칙을 지킨 코드라는 가정 위에서 동작한다. 렌더 중 side effect를 몰래 넣은 코드라면 최적화가 빗나갈 수 있으니, 도입 전 ESLint 규칙(eslint-plugin-react-hooks)부터 통과시키는 게 안전하다. Next.js라면 v15.3.1 이상에서 swc로 바로 켤 수 있다.
메모이제이션(memoization)은 "같은 입력이면 같은 결과"라는 성질을 이용해 이전 계산값을 캐싱하는 최적화다. React Compiler는 이 작업을 빌드 타임에 자동으로 끼워 넣어, 개발자가 의존성 배열을 직접 관리하던 부담과 그로 인한 버그를 줄여준다.
손맛(?)으로 useMemo를 깔던 습관을 내려놓는 게 처음엔 어색하다. 컴파일러를 실제로 켜보고 렌더 횟수를 React DevTools로 측정해본 분 있다면, 체감 차이를 댓글로 공유해주세요!
출처
- React 공식 문서 - React Compiler: Introduction
- DEV Community - React Best Practices 2026
댓글