React Hooks 도입 후 Custom Hook으로 API 호출 로직 정리하기

배경

프로젝트에 React Hooks를 본격적으로 도입하기로 했다. 기존 클래스 컴포넌트에서 componentDidMount마다 반복되던 API 호출 패턴이 있었는데, 이를 Custom Hook으로 추상화하면 코드 재사용성이 높아질 것 같았다.

기존 패턴의 문제점

각 컴포넌트마다 loading, error, data 상태를 선언하고, try-catch로 에러 처리하는 보일러플레이트가 반복됐다. 컴포넌트가 늘어날수록 유지보수 부담이 커졌다.

useFetch Hook 구현

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let isMounted = true;

    fetch(url)
      .then(res => res.json())
      .then(data => {
        if (isMounted) {
          setData(data);
          setLoading(false);
        }
      })
      .catch(err => {
        if (isMounted) {
          setError(err);
          setLoading(false);
        }
      });

    return () => {
      isMounted = false;
    };
  }, [url]);

  return { data, loading, error };
}

사용 예시

function UserList() {
  const { data, loading, error } = useFetch('/api/users');

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <ul>
      {data.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

개선 효과

코드량이 30% 정도 줄었고, API 호출 로직이 한곳에 모여 있어 에러 처리 방식을 변경할 때도 Hook만 수정하면 됐다. cleanup 함수로 언마운트 시 메모리 누수도 방지했다.

남은 과제

POST 요청이나 인증 토큰 처리는 아직 각 컴포넌트에서 직접 하고 있다. 이 부분도 Hook으로 추상화할 방법을 고민 중이다.

React Hooks 도입 후 Custom Hook으로 API 호출 로직 정리하기