React Hook 패턴 리뷰

useMemo(() => getStoredUser() ?? {}, [])
장단점 분석

localStorage에서 읽은 현재 사용자를 빈 의존성 배열로 메모이즈하는 패턴. "마운트 시 한 번만 계산"하려는 의도가 보이지만, useMemo는 그 의도에 맞는 도구가 아니다.

1이 코드가 의도하는 것

const currentUser = useMemo(() => getStoredUser() ?? {}, [])
요소의도
빈 deps []마운트 시 1회만 실행 → 매 렌더 localStorage 재읽기 방지
getStoredUser()localStorage 읽기 + JSON.parse (동기 I/O)
?? {}저장된 유저가 없으면 빈 객체로 fallback
useMemo 반환같은 객체 참조 유지로 하위 memo/effect deps 안정화

2장점

3단점 핵심 문제 다수

4더 나은 대안

A. 정말 "마운트 1회 + 변경 무관"이면 → lazy useState 권장

// 초기화 함수는 첫 렌더에서만 실행 — React가 보장한다 const [currentUser] = useState(() => getStoredUser())

"1회 실행"을 진짜로 보장하고 참조도 안정적. ?? {} 대신 null을 유지해 "유저 없음"을 명시적으로 처리.

B. 변경에 반응해야 하면 → 외부 store 구독

// useSyncExternalStore: 탭 간 동기화 + 변경 시 자동 리렌더 const currentUser = useSyncExternalStore(subscribe, getStoredUser)
이 프로젝트에서는 이미 useCurrentUser() 훅이 표준이다 (CLAUDE.md: useMe()는 금지). 직접 useMemo(getStoredUser)를 쓰지 말고 useCurrentUser()를 사용하면 stale·동기화 문제를 훅 내부가 해결한다.

C. React 19 Compiler 관점

React Compiler가 켜진 환경이라면 수동 메모이즈 대부분이 불필요하다. 참조 안정화를 위해 useMemo를 끼우기보다, 컴파일러에 맡기고 프로파일러로 확인된 병목에만 수동 memo를 남기는 것이 2026 베스트 프랙티스.

결론

이 패턴은 권장하지 않는다. 한 줄 안에 두 가지 문제가 겹쳐 있다.

대체: 변경 무관이면 useState(() => getStoredUser()), 변경 반응이 필요하면 store 구독. 이 레포에선 그냥 useCurrentUser() 를 쓰면 된다.