7.1 KiB
7.1 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frontend-react-compiler-deep | React Compiler — 자동 memoization deep | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
React Compiler Deep
React 19 의 stable feature. Compiler 가 useMemo / useCallback / React.memo 자동. 사용자 가 plain code, compiler 가 optimize.
📖 핵심 개념
- Babel plugin 가 transform.
- 매 component 의 hook 자동 추가.
- Rules of React 가 baseline.
- ESLint plugin 가 violation 감지.
💻 코드 패턴
옛 (manual)
const sorted = useMemo(() => items.sort(), [items]);
const onClick = useCallback((id) => handle(id), [handle]);
const Item = React.memo(({ item }: ItemProps) => {
return <div>{item.name}</div>;
});
새 (compiler)
// 그냥 plain.
const sorted = items.sort();
const onClick = (id) => handle(id);
const Item = ({ item }: ItemProps) => {
return <div>{item.name}</div>;
};
// Compiler 가 자동 memoize.
Setup (Vite)
import reactCompiler from 'babel-plugin-react-compiler';
export default {
plugins: [
react({
babel: { plugins: [['babel-plugin-react-compiler', { target: '19' }]] },
}),
],
};
Setup (Next.js 15+)
// next.config.js
module.exports = {
experimental: {
reactCompiler: true,
},
};
ESLint
yarn add -D eslint-plugin-react-compiler
# .eslintrc.json
{
"plugins": ["react-compiler"],
"rules": { "react-compiler/react-compiler": "error" }
}
→ Violation 가 compile 못 함.
Output (compiled)
// Input
function Counter({ count, onIncrement }) {
return <button onClick={onIncrement}>{count}</button>;
}
// Output (대략)
function Counter(props) {
const $ = _c(2);
let t0;
if ($[0] !== props.count || $[1] !== props.onIncrement) {
t0 = <button onClick={props.onIncrement}>{props.count}</button>;
$[0] = props.count;
$[1] = props.onIncrement;
$[2] = t0;
} else {
t0 = $[2];
}
return t0;
}
→ _c = useMemoCache (자동 cache).
Rules of React (compile baseline)
// ❌ Component 안 mutation 외부
let counter = 0;
function Counter() {
counter++; // 외부 mutation
return <div>{counter}</div>;
}
// ✅ State / ref 사용
function Counter() {
const [count, setCount] = useState(0);
return <div>{count}</div>;
}
Mutation 안 됨
// ❌ Props mutation
function Item({ item }) {
item.name = item.name.toUpperCase(); // mutation
return <div>{item.name}</div>;
}
// ✅ 새 object
function Item({ item }) {
const upper = item.name.toUpperCase();
return <div>{upper}</div>;
}
Effect dependency
// Compiler 가 useEffect 도 optimize.
useEffect(() => {
doSomething(value);
}, [value]);
// → 자동 dependency tracking (compiler 가 보장).
→ Linter 가 dep 체크 가 unnecessary 가 됨.
useMemo / useCallback 가 obsolete?
대부분: yes.
- Compiler 가 자동.
- 더 정확.
남은 use case:
- Manual fine-grained control.
- Compiler 옵트아웃 file.
- 매우 expensive computation (compiler 가 보장 X).
React.memo 가 obsolete?
대부분: yes.
- Compiler 가 component 자동 memo.
남은:
- 외부 lib component (compiler 가 못 보는).
- 정밀 prop comparison.
"use no memo" (옵트아웃)
'use no memo';
function Component() {
// Compiler 가 optimize X.
}
→ 안 optimize 의 file.
Performance gain
Real-world:
- 10-30% 빠름 (개발자 실수 fix).
- 큰 list = 더 큰.
- 작은 component = 작은.
→ "Manual perfect 한 코드" = gain 0.
"Manual 부족 한 코드" = 큰 gain.
Side effect detection
function Component() {
// ❌ Render 중 side effect
localStorage.setItem('x', 'y');
return <div />;
}
// → Compiler 가 거부.
// ✅
useEffect(() => {
localStorage.setItem('x', 'y');
}, []);
Conditional hook (안 됨)
// ❌
if (cond) {
useState(0); // hook 가 conditional
}
// ✅
const [x, setX] = useState(cond ? 0 : null);
Closure stale (자동 fix)
// 옛 (stale)
function Component({ value }) {
const onClick = useCallback(() => log(value), []); // dep 빠짐 = stale
return <button onClick={onClick} />;
}
// Compiler:
const onClick = () => log(value); // 자동 dep tracking.
→ Compiler 가 stale closure bug 감소.
Not a silver bullet
Compiler 가 안 fix:
- Logic bug (correct 동작 X).
- Network / async race.
- DOM manipulation 직접.
- Effect 의 timing.
→ Quality 가 매우 ↑ but not magic.
Compatibility
React 18: 부분 (experimental).
React 19+: stable.
React Native 0.75+: 가능.
Production 사용
- Meta (FB): 큰 internal.
- Anthropic Claude: 모든 React 가 compiled.
- Vercel / Next: native.
- 다양 modern app.
Migration
1. Existing app (no compiler).
2. ESLint react-compiler 활성.
3. Violation fix (1-2 일).
4. Compiler 활성.
5. Manual memo 점차 제거.
Bundle size
Compiler: 0 (build-time).
useMemoCache: 작은 runtime addition.
React 19 자체: 약간 작음.
Common violation
- Mutation in render.
- 외부 변수 변경.
- Hook 가 conditional.
- Side effect render 중.
- Function 안 hook 호출.
→ ESLint 가 모두 catch.
Testing
// React Testing Library
test('counter', () => {
const { getByText } = render(<Counter />);
fireEvent.click(getByText('+'));
expect(getByText('1')).toBeInTheDocument();
});
→ Compiler 가 transparent. Test 가 same.
Devtools
React DevTools 가 compiled component:
- "Memo" badge.
- Cache hit / miss visible.
→ Profiler 가 도움.
Profiler
import { Profiler } from 'react';
<Profiler id="App" onRender={(...) => log(...)}>
<App />
</Profiler>
Future
- Compiler stable (현재).
- Compiler 가 RSC 도 optimize.
- React Native 도.
- "Plain code, compiler 가 fast" 가 standard.
vs Solid / Svelte 5 (signal)
React Compiler: VDOM + memo.
Solid: signal (no VDOM diff).
Svelte 5: rune (signal).
→ React 가 backwards compatible.
Solid / Svelte 가 더 빠름 (specific).
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| New React app | React 19 + Compiler |
| Existing | Gradual migrate |
| Specific opt-out | "use no memo" |
| Library author | Compile by default |
| Manual control | useMemo (rare) |
| 큰 perf gap | Profile + Million.js |
❌ 안티패턴
- Manual memo + compiler: redundant.
- Mutation in render: violation.
- ESLint 무시: silent break.
- Compiler 가 fix all: profile.
- "use no memo" 모든 file: pointless.
- Side effect render 중: violation.
🤖 LLM 활용 힌트
- React Compiler = automatic memo (React 19+).
- ESLint react-compiler 가 violation catch.
- Manual useMemo 가 obsolete.
- Plain code → compiler 가 optimize.