Hooks는 컨벤션이다

862025년 11월 09일3

훅이 생태계를 지배하는 표준이 되면서, 댄은 커뮤니티에서 종종 오해가 발생하는 것을 목격했다. 많은 개발자들이 커스텀 훅을 리액트 코어에 내장된, 어떤 특별하고 마법적인 기능으로 생각하는 경향이 있었다.

useCustomHook을 호출하면, 리액트는 어떻게 그게 커스텀 훅인 줄 알고 특별하게 처리하나요?”

이러한 질문을 볼 때마다, 댄은 훅의 가장 근본적인 진실을 다시 한번 상기시켜야 할 필요성을 느꼈다.

그는 자신의 블로그에 새로운 글을 올렸다. 제목은 간결했다.
“커스텀 훅은 리액트의 기능이 아닙니다.”

글의 내용은 다음과 같았다.
“많은 분들이 오해하는 사실이 있습니다. 리액트에는 useState, useEffect 같은 내장 훅은 존재하지만, ‘커스텀 훅’이라는 개념 자체는 리액트 코어에 존재하지 않습니다.”

그는 커스텀 훅의 본질을 설명하기 위해, useWindowWidth의 코드를 다시 예로 들었다.

// 이 함수는 그냥 평범한 자바스크립트 함수입니다.
function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  // ... useEffect 로직 ...
  return width;
}

function MyComponent() {
  // 여기서 일어나는 일은, 그저 함수를 호출하는 것뿐입니다.
  const width = useWindowWidth(); 
  // ...
}

“리액트의 관점에서, MyComponent가 렌더링될 때 일어나는 일은 아주 단순합니다. MyComponent 함수가 실행되고, 그 안에서 useWindowWidth라는 또 다른 함수가 호출됩니다. 그리고 useWindowWidth 함수 안에서 useStateuseEffect가 호출되죠.”

“리액트는 useWindowWidth가 ‘커스텀 훅’이라는 사실을 전혀 모릅니다. 리액트에게 중요한 것은 오직 하나, useStateuseEffect가 호출되었다는 사실과, 그 호출이 MyComponent의 렌더링 컨텍스트 안에서, 규칙에 맞는 순서대로 일어났다는 것뿐입니다.”

그렇다면 왜 use라는 접두사를 붙이는 규칙이 필요한 것일까?

use 접두사는 리액트를 위한 규칙이 아닙니다. 그것은 ‘우리, 개발자들’을 위한 규칙입니다.”
댄이 강조했다.

“이 use라는 이름은, 이 함수가 내부적으로 다른 훅들을 호출할 것이므로, ‘훅의 규칙’을 지켜서 호출해야 한다는 것을 동료 개발자와 ESLint 플러그인에게 알려주는, 일종의 ‘사회적 약속(Social Contract)’이자 ‘컨벤션(Convention)’입니다.”

“만약 여러분이 getWindowWidth라는 이름으로 함수를 만들어도 모든 것은 똑같이 작동할 겁니다. 하지만 그렇게 하면, 린트 플러그인은 이 함수 안에서 훅을 호출하는 것이 규칙 위반인지 검사할 수 없게 되고, 동료 개발자들은 이 함수를 어떻게 사용해야 할지 혼란에 빠지게 될 겁니다.”

이 설명은 많은 개발자들의 머릿속에 있던 안개를 걷어주었다.
커스텀 훅은 마법이 아니었다.
그것은 그저, use로 시작하는 이름과 ‘훅의 규칙’ 준수라는 두 가지 약속 위에 세워진, 지극히 평범한 자바스크립트 함수였다.

하지만 바로 그 단순한 컨벤션이, 리액트 개발자들에게 로직을 재사용하고 공유하는, 이전과는 비교할 수 없는 강력한 힘을 부여한 것이다.

이 깨달음은 훅을 더욱 신비롭지 않고, 예측 가능한 도구로 만들었다.
개발자들은 이제 리액트의 마법에 의존하는 대신, 자바스크립트의 기본 원리와 몇 가지 단순한 규칙만으로도 강력한 추상화를 만들어낼 수 있다는 자신감을 갖게 되었다.

훅의 멘탈 모델은 더욱 단단해지고 있었다.
그리고 사람들은 이제, 훅이 지배하는 새로운 시대의 관점에서, 과거의 유산이었던 클래스 컴포넌트를 어떻게 바라보아야 할지 고민하기 시작했다.