useToggle과 useInput은 useState와 useCallback만을 사용한, 비교적 단순한 커스텀 훅이었다. 이제 리액트 팀은 useEffect를 포함하는, 즉 컴포넌트의 생명주기와 상호작용하는 더 복잡한 로직을 캡슐화하는 도전에 나섰다.
그들이 선택한 예제는, 이전에 댄이 커스텀 훅의 가능성을 처음 발견했던 바로 그 시나리오, ‘브라우저 창 너비 추적’ 로직이었다. 이 로직은 상태 관리(useState)와 부수 효과(useEffect)가 모두 필요한, 커스텀 훅의 힘을 보여주기에 완벽한 예제였다.
소피는 팀원들 앞에서, 이 로직을 커스텀 훅으로 만들어가는 과정을 단계별로 시연했다.
“우리의 목표는, 어떤 컴포넌트에서든 const width = useWindowWidth(); 한 줄만으로 현재 창의 너비를 알 수 있게 하는 것입니다.”
그녀는 useWindowWidth.js라는 새로운 파일을 만들고, 함수를 정의했다.
import { useState, useEffect } from 'react';
function useWindowWidth() {
// ... 로직을 여기에 구현 ...
}
첫 번째 단계는, 창의 너비를 저장할 상태를 만드는 것이었다.
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
// ...
}
두 번째 단계는, resize 이벤트를 감지하여 width 상태를 업데이트하는 부수 효과를 설정하는 것이었다.
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
// 창 크기가 변경될 때마다 width 상태를 업데이트하는 핸들러
const handleResize = () => setWidth(window.innerWidth);
// 'resize' 이벤트에 핸들러를 등록한다 (구독)
window.addEventListener('resize', handleResize);
// 클린업 함수: 컴포넌트가 사라질 때 이벤트 리스너를 제거한다 (구독 해지)
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // 이 효과는 컴포넌트 마운트 시 한 번만 실행되면 된다.
// ...
}
useEffect 블록 안에는 이벤트 리스너를 등록하는 로직과, 클린업 함수를 통해 그것을 해제하는 로직이 완벽한 한 쌍으로 존재했다. componentDidMount와 componentWillUnmount에서 하던 일이 이 하나의 블록 안에서 모두 처리되었다.
마지막 단계는, 이렇게 관리되는 width 상태를 훅의 최종 결과물로 반환하는 것이었다.
function useWindowWidth() {
// ... (useState와 useEffect 로직) ...
return width;
}
이제, useWindowWidth라는 이름의 강력하고 재사용 가능한 커스텀 훅이 완성되었다.
이 훅은 내부적으로 상태를 가지고, 컴포넌트의 생명주기와 연동하여 브라우저 이벤트를 구독하고 해지하는, 살아있는 로직 덩어리였다.
이 훅을 사용하는 것은 놀랍도록 간단했다.
function MyResponsiveComponent() {
const width = useWindowWidth();
return (
<p>
{width > 800
? 'This is a wide screen.'
: 'This is a narrow screen.'}
</p>
);
}
MyResponsiveComponent는 창 너비를 어떻게 추적하는지, 이벤트 리스너를 어떻게 관리하는지 전혀 알 필요가 없었다. 그저 useWindowWidth라는 훅을 호출하여, 결과값만 가져다 쓸 뿐이었다. 모든 복잡성은 커스텀 훅의 장막 뒤로 감춰졌다.
이것은 useEffect를 포함한 커스텀 훅의 진정한 힘을 보여주는 순간이었다.
개발자들은 이제 생명주기와 관련된 복잡한 로직들—구독, 타이머, 애니메이션 등—을 재사용 가능한 부품으로 만들어, 레고 블록처럼 쉽게 조립할 수 있게 되었다.
리액트 개발의 패러다임이 완전히 바뀌고 있었다.
컴포넌트를 조합하여 UI를 만드는 것을 넘어, 훅을 조합하여 로직을 만드는 시대로 진입하고 있었다.
팀의 시선은 이제 더 높은 곳을 향했다.
단순한 브라우저 API 연동을 넘어, 웹 개발의 가장 핵심적인 과제인 ‘비동기 데이터 통신’을 다루는 커스텀 훅을 만들어 볼 차례였다. 그 도전은 훗날 react-query나 SWR 같은 거대한 라이브러리의 탄생을 예고하는, 중요한 첫걸음이 될 터였다.


