--- id: wiki-2026-0508-l-component-lifecycle-hooks title: Lifecycle Hooks category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Lifecycle, Component Lifecycle, useEffect, ngOnInit, onMount] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [frontend, react, vue, angular, svelte, lifecycle] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: react --- # Lifecycle Hooks ## 매 한 줄 > **"매 컴포넌트의 생애주기 훅"**. mount/update/unmount 시점에 부수효과를 거는 표준 메커니즘. React 는 `useEffect` 단일화, Vue/Angular/Svelte 는 명명된 훅 제공. ## 매 핵심 ### 매 공통 phase 1. **Create**: instance 생성, props 수신. 2. **Mount**: DOM 진입 — 이벤트 바인딩, 데이터 fetch. 3. **Update**: state/props 변경 — derived 갱신. 4. **Unmount**: DOM 제거 — cleanup (timer, listener, subscription). 5. **Error**: 자식 throw 잡기. ### 매 framework 매핑 | Phase | React | Vue 3 | Angular | Svelte | |---|---|---|---|---| | Mount | `useEffect(fn, [])` | `onMounted` | `ngOnInit` | `onMount` | | Update | `useEffect(fn, [dep])` | `watch` | `ngOnChanges` | `$:` reactive | | Unmount | return cleanup | `onUnmounted` | `ngOnDestroy` | `onDestroy` | | Error | `ErrorBoundary` | `onErrorCaptured` | `ErrorHandler` | (없음, try/catch) | ### 매 React 19 메모 - StrictMode 가 `useEffect` 를 dev 에서 2회 실행 → cleanup 필수. - Server Component 는 lifecycle 없음 (그냥 async function). - `use` hook 으로 promise 직접 read 가능. ## 💻 패턴 ### React: 마운트시 fetch + cleanup ```tsx useEffect(() => { const ctrl = new AbortController(); fetch(`/api/user/${id}`, { signal: ctrl.signal }) .then(r => r.json()).then(setUser); return () => ctrl.abort(); }, [id]); ``` ### React: subscribe pattern ```tsx useEffect(() => { const sub = store.subscribe(setState); return () => sub.unsubscribe(); }, []); ``` ### Vue 3 Composition API ```vue ``` ### Angular standalone component ```typescript @Component({ selector: "app-x", standalone: true, template: "..." }) export class XComponent implements OnInit, OnDestroy { private sub?: Subscription; constructor(private svc: DataService) {} ngOnInit() { this.sub = this.svc.stream$.subscribe(v => (this.value = v)); } ngOnDestroy() { this.sub?.unsubscribe(); } } ``` ### Svelte 5 (with runes) ```svelte ``` ### React custom hook (encapsulate lifecycle) ```tsx function useInterval(cb: () => void, ms: number) { const ref = useRef(cb); useEffect(() => { ref.current = cb; }, [cb]); useEffect(() => { const id = setInterval(() => ref.current(), ms); return () => clearInterval(id); }, [ms]); } ``` ### Error boundary (React) ```tsx class Boundary extends React.Component { state = { err: null }; static getDerivedStateFromError(err) { return { err }; } componentDidCatch(err, info) { logger.error(err, info); } render() { return this.state.err ? : this.props.children; } } ``` ## 매 결정 기준 | 작업 | 적절한 훅 (React) | |---|---| | 1회 fetch on mount | `useEffect(fn, [])` | | dep 변경시 refetch | `useEffect(fn, [dep])` | | DOM 측정 | `useLayoutEffect` | | 외부 store 구독 | `useSyncExternalStore` | | Render 동안 동기화 | derived state, **NOT** effect | **기본값**: 가능하면 effect 안 쓰고 derived 로 처리. effect 는 "외부 시스템 동기화" 전용. ## 🔗 Graph - 변형: [[useEffect]], [[ngOnInit]], [[onMount]] - 응용: [[Data-Fetching]] - Adjacent: [[Custom-Hooks]], [[Error-Boundaries]], [[Server-Components]] ## 🤖 LLM 활용 **언제**: 외부 시스템(timer, socket, listener) 결합, mount-once init, prop-driven refetch. **언제 X**: pure 계산 — useMemo/derived 로 충분, useEffect 남용은 안티패턴. ## ❌ 안티패턴 - **Effect 안 dep 누락**: stale closure → 버그 끝판왕. - **Cleanup 미작성**: timer/listener leak, StrictMode 에서 즉시 들킴. - **상태를 effect 로 동기화**: derived state 가 정답. - **Async useEffect 함수**: `useEffect(async () => ...)` 안 됨. 안에서 async fn 호출. - **ngOnChanges 에서 setState 무한 루프**: 입력 비교 필수. ## 🧪 검증 / 중복 - React docs (You Might Not Need an Effect), Vue 3 / Angular / Svelte 5 공식 문서. - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — 4 framework 매핑표, useEffect 안티패턴, Svelte 5 runes |