--- id: react-strict-mode-effects title: React StrictMode 의 의도적 이중 실행 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [react, strict-mode, dev-only, vibe-coding] tech_stack: { language: "TypeScript / React 18+", applicable_to: ["Web", "React Native"] } applied_in: [] aliases: [double rendering, dev mode, side-effect detection] --- # React StrictMode 의도적 이중 실행 > StrictMode 는 **dev 환경에서 effect / 컴포넌트 / state initializer 를 의도적으로 두 번 실행**해 cleanup 누락 / 비순수 코드를 노출. production 에선 한 번. "두 번 실행되는 게 비정상이다" 가 아니라 "두 번 실행되어도 같아야 한다" 가 맞음. ## 📖 핵심 개념 StrictMode 가 두 번 실행하는 것: function component body, useEffect (mount → cleanup → mount), useState/useReducer initializer, useMemo factory. 목적: **idempotent + cleanup 검증**. 한 번 실행과 두 번 실행 결과가 같으면 향후 React 의 offscreen 렌더 / 재마운트 최적화에 안전. ## 💻 코드 패턴 ```tsx // ❌ 두 번 실행 시 사고 useEffect(() => { socket.connect(); // 두 번 호출 → 두 connection }, []); // ✅ cleanup 으로 idempotent useEffect(() => { socket.connect(); return () => socket.disconnect(); }, []); // ✅ initializer 도 pure const [counter] = useState(() => loadFromStorage()); // OK if pure read const [id] = useState(() => Math.random()); // ❌ 두 번 실행되면 다른 id const [id] = useState(() => crypto.randomUUID()); // 같은 문제 // → useRef 또는 lazy ref pattern const idRef = useRef(); if (idRef.current === undefined) idRef.current = crypto.randomUUID(); ``` ## 🤔 의사결정 기준 | 상황 | StrictMode-friendly 패턴 | |---|---| | WebSocket / EventSource 연결 | connect/disconnect cleanup | | 외부 라이브러리 init (chart, map) | init/destroy cleanup | | analytics ping (mount 시 1회) | useEffect 안 쓰고 onClick / 라우터 이벤트로 | | 한 번만 실행되는 unique id | useRef 패턴 | | 비싼 fetch (두 번 호출 부담) | React Query / SWR — 자체 dedup | ## ❌ 안티패턴 - **StrictMode 끄기**: 단기 회피. 사고 잠재. 켜놓고 root cause 수정. - **`if (didMountRef.current) return; didMountRef.current = true;`**: hack. 진짜 문제는 cleanup 미흡. - **production 에서도 같은 문제 해결되었다고 가정**: prod 는 한 번 실행 — dev StrictMode 가 미래의 unmount/remount 시뮬. - **useEffect 의 cleanup 안에서 또 mutation**: cleanup 도 idempotent. ## 🤖 LLM 활용 힌트 - "StrictMode 가정. effect 가 두 번 실행되어도 안전한가?" 라고 매번 점검. - 외부 라이브러리 init 코드는 cleanup destroy 와 페어로. ## 🔗 관련 문서 - [[React_useEffect_Pitfalls]] - [[Idempotent_Operations]]