description: "React Hooks 설계 원칙 및 사용 규칙" paths:
하나의 훅은 하나의 관심사만 다룬다. 여러 역할이 섞이면 분리한다.
// ❌ 너무 많은 역할
function useUserDashboard() { /* 인증 + 데이터 + UI 상태 전부 */ }
// ✅ 역할 분리
function useAuth() { /* 인증만 */ }
function useUserData(userId: string) { /* 데이터만 */ }
다음 중 하나라도 해당하면 커스텀 훅으로 추출한다:
useEffect + 관련 state가 3개 이상 묶임클린업 함수를 항상 반환한다 (이벤트 리스너, 타이머, 구독 등).
useEffect(() => {
const handler = (e: Event) => { /* ... */ };
window.addEventListener("resize", handler);
return () => window.removeEventListener("resize", handler);
}, []);
빈 의존성 배열([])은 마운트/언마운트에만 실행됨을 의미한다. 의존성을 의도적으로 생략하는 것은 금지.
useCallback, useMemo는 실제 성능 문제가 있을 때만 사용한다. 선제적 최적화는 오히려 코드를 복잡하게 만든다.
적합한 경우:
React.memo로 감싸져 있을 때// ✅ 자식에게 전달되는 핸들러
const handleSubmit = useCallback(() => {
onSubmit(formData);
}, [formData, onSubmit]);
// ❌ 단순 이벤트 핸들러에 불필요한 useCallback
const handleClick = useCallback(() => setOpen(true), []); // 과잉
브라우저 전용 API 접근 시 반드시 체크한다.
// ✅ 초기값에서 체크
const [value, setValue] = useState(() => {
if (typeof window === "undefined") return null;
return localStorage.getItem(key);
});
// ✅ effect에서 체크
useEffect(() => {
if (typeof window === "undefined") return;
// browser-only code
}, []);
use 접두사 필수useXxx (조회), useSaveXxx (저장), useDeleteXxx (삭제)isLoading, isOpen, hasError"SSR Safety 부분에 useIsClient 커스텀 훅 패턴도 추가되면 좋겠어요. typeof window 체크를 매번 하기보다 훅으로 빼서 쓰는 경우가 많아서요."