컴포넌트에서 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
: 데이터 요청 함수
- 네트워크 요청 전 로딩 상태를 true로 만든다.
- 데이터를 요청한다.
- 응답을 상태로 저장한다.
- 요청이 끝났으니 로딩 상태를 false로 바꾼다.
- 응답을 반환한다.
setTimeout
은 로컬 호스트에서는 지연되는 일이 거의 없기 때문에 딜레이를 줘서 로딩이 있는 것 처럼 하기위해서 사용했다. 그런데 setTimeout
은 사용하면 응답을 밖으로 리턴할 수 없다.
이제 초기 렌더링 데이터를 요청하고 응답 데이터를 컴포넌트로 내보내는 로직을 추가해 보자.
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 메서드는 꼭 초기 데이터가 아니더라도 요청할 수 있도록 내보내줬다.
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 메서드를 제공하기에 나도 리팩터링은 하지 않았다.