본문 바로가기
3주차

fetch와 useState로 직접 구현하는 Custom Query Hook

by 곽지욱 2025. 5. 2.

React Query, SWR 등 유용한 데이터 패칭 라이브러리가 많지만, 때때로 가볍게 fetch만으로 구현하고 싶은 상황도 있어요. 이번 글에서는 fetch, useState, useEffect만으로 로딩, 에러 처리 포함된 데이터 패칭 로직을 직접 구현해볼거에요.

구현 조건

  1. fetch를 사용해서 데이터 요청
  2. 로딩 중에는 "loading..." 텍스트 표시
  3. 에러 발생 시 메시지를 화면에 표시
  4. 컴포넌트가 unmount 되었을 때 상태를 업데이트하지 않도록 isMounted 처리 포함

여기서 중요한 부분은 의외로 리액트의 생명주기와 관련있어요.

React는 unmount 된 상태에서 상태 변경 하는 것을 허용하지 않아요.

 

예를 들어 사용자가 데이터를 기다리는 중에 화면을 빠르게 전환하면 해당 컴포넌트는 사라지고(unmount) 이후 fetch 응답이 도착하더라도 setState가 호출되면 에러가 발생하게 돼요.

 

이를 방지하려면 컴포넌트의 생명 주기를 추적할 수 있는 inMounted 플래그를 사용해야 해요.

import { useEffect, useState } from "react";

export function useCustomQuery(url) {
  const [data, setData] = useState(null);
  const [isLoading, setLoading] = useState(true);
  const [error, setError] = useState(null);

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

    async function fetchData() {
      setLoading(true);
      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error("네트워크 응답 없음");
        const json = await response.json();
        if (isMounted) {
          setData(json);
          setLoading(false);
        }
      } catch (err) {
        if (isMounted) {
          setError(err);
          setLoading(false);
        }
      }
    }

    fetchData();

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

  return { data, isLoading, error };
}

핵심적인 부분은 다음과 같아요.

 

setLoading 을 fetch 시작 직전에 호출해줘요.

 

그리고 fetch 응답 후 실패하는 경우, 성공하는 경우 모두에서 setLoading(false)를 호출해줘요.

 

isMounted는 컴포넌트가 살아있는지 확인하여 안전하게 상태를 업데이트 해주는 역할을 해요.

 

마지막으로 useEffect cleanUp 함수에서 isMounted = false를 설정해줘요.

 

이 같은 custom 훅은 컴포넌트에서 이렇게 사용할 수 있어요.

function UserList() {
  const { data, isLoading, error } = useCustomQuery("https://jsonplaceholder.typicode.com/users");

  if (isLoading) 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>
  );
}

fetch와 useState, useEffect 만으로 직접 커스텀 훅을 만들어 보는 것은 비동기 흐름과 상태 관리의 본질을 이해하는 것에 도움이 돼요.

 

라이브러리는 많은 로직을 추상화 해주기 때문에, 그 내부 로직이 어떻게 구상되어있는지 모를 수 있어요. 글에서 소개된 내용도 많은 부분들이 생략되었지만,

 

직접 구현을 해보면 로딩 상태가 언제 시작되고, 언제 종료되는지, 에러 발생 흐름이 어떻게 되는지를 명확하게 이해할 수 있어요.

'3주차' 카테고리의 다른 글

다양하게 상태 관리 하기 💿  (0) 2025.05.02
왜 콘솔에 값이 이상하게 찍히지?  (3) 2025.05.02
react의 props와 state  (0) 2025.05.02
JavaScript 패키지 매니저 비교하기  (0) 2025.05.02
🐛 왜 yarn 이어야 할까?  (0) 2025.05.02