React Hooks와 Hooks 규칙 – 나에게 드디어 와닿은 이해
Source: Dev.to

오늘, 무언가가 깨달아졌습니다.
오랫동안 React Hooks를 사용해 왔지만, 솔직히 말하면 그것이 무엇인지, 왜 React가 그 규칙에 그렇게 엄격한지, 그리고 동작하는 것처럼 보이는 일부 패턴이 왜 여전히 나쁜 관행으로 간주되는지 진정으로 이해하지 못했습니다.
이 블로그는 제가 개인적으로 이해한 내용을 적어보려는 시도이며, 이를 통해:
- 일주일이나 이주일 후에 다시 읽을 때
- 혹은 앞으로 혼란스러워질 때
이 글이 저를 완전한 명확성으로 되돌아오게 해 주고, 단순히 겉핥기식 지식에 머무르지 않게 해 주길 바랍니다.
실제 React Hooks가 무엇인가
첫 번째 오해가 바로 이것이었습니다:
Hooks는 단순한 헬퍼 함수가 아니다.
Hooks는 React가 제공하는 특수한 빌딩 함수이며, React의 Fiber 아키텍처와 직접적으로 상호 작용합니다.
Hooks는 다음을 위해 사용됩니다:
- React에 상태를 등록하기
- 부수 효과(side effects)를 등록하기
- 컴포넌트 로직을 React 내부 업데이트 시스템에 연결하기
그래서 다음과 같은 특징이 있습니다:
- 모든 Hook은
use로 시작합니다 (useState,useEffect,useRef등) - React는 Hook을 일반 JavaScript 함수처럼 취급하지 않습니다 – Hook은 React가 컴포넌트를 렌더링하고 업데이트하는 방식과 밀접하게 결합되어 있습니다.
Hooks와 React Fiber – 놓친 정신 모델
내부적으로 React는 Fiber Tree를 유지합니다. 각 컴포넌트 렌더링마다 React는 훅을 연결 리스트에 저장합니다:
- 첫 번째 훅 호출은 첫 번째 노드가 됩니다
- 두 번째 훅 호출은 두 번째 노드가 됩니다
- …이와 같이 계속됩니다
React는 훅을 이름으로 식별하지 않고 순서로 식별합니다. 이 한 가지 사실이 모든 Hooks 규칙을 설명합니다.
React Hooks 개요
React는 많은 훅을 제공하지만, 실제로 가장 흔히 쓰이는 그룹은 다음과 같습니다:
가장 많이 사용되는 훅
useStateuseEffectuseReduceruseContext
성능 / 최적화 훅
useRefuseCallbackuseMemouseTransitionuseDeferredValue
저수준 또는 고급 훅
useSyncExternalStoreuseInsertionEffect
각 훅은 목적이 다르지만 모든 훅에 동일한 규칙이 적용됩니다.
훅 규칙 (마침내 이해된 부분)
✅ 규칙 1: 훅은 최상위에서만 호출한다
if문 안에 훅을 두지 않는다- 루프 안에 훅을 두지 않는다
return뒤에 훅을 두지 않는다
훅은 절대 조건부로 실행되어서는 안 된다.
잘못된 패턴 예시
if (imdbRating > 8) {
const [isTop, setIsTop] = useState(true);
}
왜 위험한가: 훅이 일부 렌더에서는 실행되고 다른 렌더에서는 실행되지 않을 수 있어, 훅 순서가 깨지고 React가 상태를 올바르게 매칭하지 못한다.
✅ 규칙 2: 훅은 React 함수에서만 호출한다
훅은 다음 내부에서만 허용된다:
- 함수형 컴포넌트
- 커스텀 훅
일반 JavaScript 함수에서는 호출해서는 안 된다. React는 렌더링 단계에서만 훅을 추적하기 때문이다.
“이 코드는 동작하지만… 왜 여전히 잘못된 걸까?”
파생 상태 함정
예전에는 이렇게 해도 괜찮다고 생각했습니다:
const [isTop, setIsTop] = useState(imdbRating > 8);
useEffect(() => {
setIsTop(imdbRating > 8);
}, [imdbRating]);
코드는 오류 없이 실행되지만, 개념적으로 불필요한 상태를 만들고 설계가 나빠집니다.
올바른 사고 방식: 저장하지 말고 파생하라
값을 props나 다른 상태에서 완전히 파생할 수 있다면, 별도의 상태로 저장하지 말아야 합니다.
const isTop = imdbRating > 8;
추가 상태도, 효과도, 추가 렌더링도 없으므로 로직이 더 깔끔해지고 버그가 줄어듭니다.
평균 평점에 대한 상태 업데이트 이해
새로운 상태가 이전 상태에 의존할 때는 함수형 업데이트를 사용합니다:
// Direct update
setAvgRating(Number(imdbRating));
// Functional update (depends on previous value)
setAvgRating(prev => (prev + userRating) / 2);
React는 직접 업데이트와 함수형 업데이트를 모두 지원합니다. 함수형 업데이트를 사용하면 다음과 같은 문제를 피할 수 있습니다:
- 오래된 값 사용
- 배치 처리로 인한 예기치 않은 동작
이제 나는 훅을 이렇게 시각화한다
- Hooks = 연결 리스트의 노드
- React = 그 리스트를 관리하는 매니저
- 순서를 바꾸면 = ❌ 시스템이 깨짐
따라서, 훅은 렌더링마다 같은 순서로 호출되어야 하며, 조건문 안에 넣어서는 안 된다.
최종 깨달음
The Rules of Hooks are:
- 임의적이지 않음
- “React가 이유 없이 엄격한 것”이 아님
They are a direct result of React’s internal design. Once I understood Fiber and hook ordering, I didn’t need to memorize the rules—they started making logical sense.
최종 생각
React Hooks에 어려움을 겪고 있다면:
- 사용법만 배우지 말고 왜 존재하는지 배우세요.
“왜”가 명확해지면:
- 코드가 더 깔끔해집니다
- 버그가 줄어듭니다
- 자신감이 높아집니다
이 블로그는 미래의 나를 위해서도 씁니다 — 이 혼란이 다시는 돌아오지 않도록.