본문 바로가기

TroubleShooting

리액트 API 호출 구조 리팩토링: useEffect에서 React Query로의 전환

반응형

1. 발생 이슈

기존 프로젝트에서는 컴포넌트 내에서 useEffect와 axios.get을 직접 사용하는 방식으로 데이터를 페칭했습니다. 하지만 프로젝트의 규모가 커지면서 다음과 같은 관리 효율성 저하 문제가 발생했습니다.

  • 코드 중복: 모든 컴포넌트에서 인증 헤더(Token) 설정, 로딩/에러 상태 관리(useState)가 반복됨.
  • 컴포넌트 비대화: UI 렌더링에 집중해야 할 컴포넌트 파일에 API 호출, 데이터 가공 등의 비즈니스 로직이 섞여 가독성이 떨어짐.
  • 성능 문제: 동일한 데이터를 여러 곳에서 사용할 때 중복 호출이 발생하며, 클라이언트 측 캐싱이 전혀 이루어지지 않음.

2. 원인 분석

  • 관심사 분리(SoC)의 부재: UI 레이어와 네트워크 레이어가 강하게 결합(Strong Coupling)되어 있어 하나를 수정하려면 다른 하나도 같이 수정해야 하는 의존성이 발생함.
  • 명령형 데이터 페칭의 한계: useEffect는 데이터 페칭 시점과 상태 변경을 일일이 개발자가 제어해야 하므로, 네트워크 지연이나 에러 발생 시 예외 처리가 누락되기 쉬운 구조임.

3. 해결 방법

계층화된 아키텍처를 도입하여 선언적(Declarative) 데이터 페칭 구조로 리팩토링했습니다.

① Network Layer (Axios Instance)

axios.create를 활용해 기본 설정을 모듈화하고, 인터셉터를 통해 공통 로직을 처리했습니다.

JavaScript

// src/api/axiosInstance.js
const api = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
  headers: { 'Content-Type': 'application/json' }
});

api.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

② Service Layer (API Function)

엔드포인트별로 함수를 관리하여 API 스펙 변경 시 대응력을 높였습니다.

JavaScript

// src/api/userApi.js
export const fetchUserProfile = (userId) => api.get(`/users/${userId}`).then(res => res.data);

③ Data Access Layer (Custom Hooks & React Query)

TanStack Query를 도입하여 데이터 상태(Loading, Error, Caching)를 전역적으로 관리했습니다.

JavaScript

// src/hooks/useUser.js
export const useUser = (userId) => {
  return useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUserProfile(userId),
  });
};

4. 결과 및 배운점

결과

  • 유지보수성 향상: API 주소나 공통 에러 처리를 한 곳(axiosInstance)에서 관리할 수 있게 됨.
  • 선언적 UI 구현: 컴포넌트에서는 const { data, isLoading } = useUser() 한 줄로 데이터를 가져와 사용하게 되어 코드가 매우 간결해짐.
  • 사용자 경험(UX) 개선: React Query의 캐싱 시스템을 통해 불필요한 네트워크 요청을 줄이고, 페이지 전환 시 부드러운 데이터 로딩 환경을 구축함.

배운점 (Key Takeaways)

  • 추상화의 중요성: 단순히 코드를 줄이는 것이 아니라, "어떤 레이어가 어떤 역할을 할 것인가"를 명확히 하는 것이 팀 단위 프로젝트에서 얼마나 중요한지 깨달음.
  • 라이브러리 도입의 근거: 단순히 유행하는 기술(React Query)을 쓰는 것이 아니라, 기존 useEffect 방식이 가진 한계를 명확히 인지하고 그 대안으로서 도구를 선택하는 사고 과정을 경험함.
  • 비즈니스 로직의 독립: 컴포넌트는 오직 "어떻게 보여줄 것인가"에만 집중하고, 데이터가 "어디서 어떻게 오는지"는 신경 쓰지 않게 설계하는 것이 유연한 코드의 핵심임을 배움.
반응형