← ClaudeAtlas

react-expertlisted

React 컴포넌트를 설계·구현·리팩터링하거나 상태 관리, useEffect 남용, 리렌더 성능, 접근성 문제를 다룰 때 사용한다. React 19 기준.
LeeYudok/doksam-skills · ★ 10 · Web & Frontend · score 77
Install: claude install-skill LeeYudok/doksam-skills
# react-expert 컴포넌트 코드가 대상이다. 번들러·패키지 매니저·의존성은 `frontend-build`, 디자인 토큰·컴포넌트 선택은 `doksam-ui` 가 맡는다. 이 문서는 **일반론을 적지 않는다.** 판단이 갈리는 지점, 자주 틀리는 곳, React 19 에서 바뀐 것만 담는다. ## 1. 상태는 필요한 만큼만, 있어야 할 곳에 판단 순서: 1. **props 나 기존 상태에서 계산할 수 있는가** → 렌더 중에 계산한다. `useState` + `useEffect` 조합으로 파생값을 동기화하지 않는다. 이 패턴이 버그의 큰 축이다. 2. **여러 컴포넌트가 공유하는가** → 가장 가까운 공통 부모로 올린다. 전역 스토어는 "여러 화면이 같은 서버 상태를 본다"가 성립할 때만. 3. **URL 에 있어야 하는가** — 새로고침·공유·뒤로가기가 의미 있으면 라우터 상태다. 상세 화면·필터·탭이 여기 해당한다. ```tsx // 나쁨 — 파생값을 상태로 두고 동기화 const [filtered, setFiltered] = useState<Room[]>([]) useEffect(() => { setFiltered(rooms.filter(r => r.name.includes(q))) }, [rooms, q]) // 좋음 — 렌더 중 계산 const filtered = useMemo(() => rooms.filter(r => r.name.includes(q)), [rooms, q]) ``` `useMemo` 는 **측정 가능한 비용이 있을 때만**. 배열 몇 개 도는 것에 붙이면 코드만 늘어난다. ## 2. useEffect 는 "외부 시스템과 동기화"에만 effect 를 쓰기 전에 답한다: **이 코드가 맞물리려는 외부 시스템이 무엇인가?** (네트워크, DOM 이벤트, 타이머, 구독) 답이 없으면 effect 가 아니다. - **사용자 행동의 결과는 이벤트 핸들러에서 처리한다.** 상태를 바꾸고 그 변화를 effect 로 감지해 후속 작업을 하는 구조는 흐름을 끊고 중복 실행을 부른다. - **StrictMode 에서 effect 는 두 번 실행된다.** 이건 버그가 아니라 정리(cleanup) 누락을 드러내는 장치다. 두 번 돌아 깨지면 effect 쪽을 고친다. ### 비동기 요청 취소는 필수 ```tsx useEffect(() => { let alive = true api.messages(dbRef, roomId).then(m => { if (alive) setMessages(m) }) return () => { alive = false } }, [dbRef, roomId]) ``` 빠뜨리면 대상을 연달아 바꿀 때 **먼저 보낸 응답이 나중에 도착해 ���면을 덮는다**(경합). `AbortController` 를 쓸 수 있으면 그쪽이 더 낫다 — 요청 자체를 끊는다. ### 의존성 배열을 거짓말로 채우지 않는다 린트가 요구하는 값을 빼서 "한 번만 실행"