[리액트] useFetch 커스텀 훅 만들기

·2022년 10월 20일
0

공부한 것

목록 보기
35/58

컴포넌트에서 http 요청을 하는 로직을 분리하기 위해 useFetch라는 커스텀 훅을 만들었다.

export function useFetch({ baseUrl, options, endPoint }: UseFetchParams) {
  const [responseData, setResponseData] = useState<any>();
  const [loading, setLoading] = useState(false);

  const fetchData = async (
    url: string,
    method: string,
    options?: RequestInit
  ) => {
    try {
      setLoading(true);

      //setTimeout(async () => {
      const response = options
        ? await fetch(url, { ...options, method })
        : await fetch(url);
      const { data } = await response.json();
      setResponseData(data);
      setLoading(false);
      return data;
      //}, 2000);
    } catch (err) {
      console.error(err);
      return null;
    }
  };

  return { loading };
}

responseData : 응답 데이터를 내보내기 위한 상태
loading : 요청이 진행 중인지를 알기 위한 상태
fetchData : 데이터 요청 함수

fetchData 로직

  1. 네트워크 요청 전 로딩 상태를 true로 만든다.
  2. 데이터를 요청한다.
  3. 응답을 상태로 저장한다.
  4. 요청이 끝났으니 로딩 상태를 false로 바꾼다.
  5. 응답을 반환한다.

setTimeout은 로컬 호스트에서는 지연되는 일이 거의 없기 때문에 딜레이를 줘서 로딩이 있는 것 처럼 하기위해서 사용했다. 그런데 setTimeout은 사용하면 응답을 밖으로 리턴할 수 없다.

메서드 추가

초기 데이터 요청, get

이제 초기 렌더링 데이터를 요청하고 응답 데이터를 컴포넌트로 내보내는 로직을 추가해 보자.

export function useFetch({ baseUrl, options, endPoint }: UseFetchParams) {
  //...
    const createUrl = (endPoint: string) => `${baseUrl}${endPoint}`;

    const get = async ({ endPoint, options }: GetParams) => {
      const method = "GET";
      const url = createUrl(endPoint);
      const data = options
        ? await fetchData(url, method, options)
        : await fetchData(url, method);
      return data;
    };

    useEffect(() => {
      if (endPoint) {
        get({ endPoint, options });
      }
    }, []);
  
  return { loading, data : responseData, get };
}

초기 데이터의 경우에는 외부에서 get 메서드를 사용하지 않고 useFetch를 호출하는 과정에서 바로 데이터 요청을 할 수 있도록 내부에서 useEffect를 사용했다.
원래 컴포넌트에서 useEffect를 사용해 데이터를 호출하는 로직을 그대로 useFetch라는 함수로 감싼 것뿐이다.
get 메서드는 꼭 초기 데이터가 아니더라도 요청할 수 있도록 내보내줬다.

post

get 외에 다른 http 요청들을 할 수 있도록 post 메서드를 만들어 내보내기로 했다.

export function useFetch({ baseUrl, options, endPoint }: UseFetchParams) {
  //...
    const post = async ({ endPoint, options }: PostParams) => {
      const { headers } = options;
      const { method }: { method: Method } = headers;

      if (!method) {
        throw "HTTP method를 입력하세요.";
      }
      const url = createUrl(endPoint);
      const data = await fetchData(url, method, options);
      return data;
    };
  
  return { loading, data : responseData, get, post };
}

구현하고 보니 로직이 비슷해 하나로 사용할 수 있을 것 같아서 get 메서드와 로직을 분리할 필요가 있었을까 하는 생각이 들었는데, 한편으로는 get, post 이렇게 따로 있는 게 더 직관적이지 않을까 싶기도 하고...use-http 라이브러리를 봤는데 post 메서드를 제공하기에 나도 리팩터링은 하지 않았다.

0개의 댓글