useFetch란?
서버에서 Fetch한 데이터를 상태값에 넣어 트랙킹하고, 로딩과 에러 상태까지 관리하여 사용하는 유용한 훅이다.
코드 살펴보기
1 . 간단 버전
function useFetch(url) {
// 응답 JSON값
const [responseJSON,setResponseJSON] = useState(null);
// 로딩 상태값
const [isLoading,setIsLoading] = useState(true);
// 에러 상태값
const [error,setError] = useState(null);
useEffect(()=>{
// unMount시 cancel하기 위한 변수
let shouldCancel = false;
const callFetch = async () => {
setIsLoading(true);
try {
// 응답 성공 시
const response = await fetch(url);
const newResponseJSON = await response.json();
if(shouldCancel) return;
setResponseJSON(newResponseJSON);
setError(null);
} catch (newError) {
// 응답 실패 시
if(shouldCancel) return;
setError(newError);
setResponseJSON(null);
}
// 로딩은 응답 실패하나 성공하나 false로 변경
setIsLoading(false)
}
callFetch();
return () => {
shouldCancel = true
}
},[url])
return {
responseJSON,
isLoading,
error
}
}
2. reducer 사용 버전 (advanced 버전)
function reducer(state,{type,responseJSON,error}) {
switch(type) {
case 'loading':
return {...state,isLoading:true};
case 'success':
return {responseJSON,isLoading:false,error:null};
case 'error':
return {responseJSON:null,isLoading:false,error};
default:
throw new Error('Unknown action type');
}
}
function useFetch(url) {
const [state,dispatch] = useReducer(reducer,{
responseJSON:null,
isLoading:true,
error:null
})
useEffect(()=>{
let shouldCancel = false;
const callFetch = async () => {
dispatch({type:'loading'})
try {
const response = await fetch(url);
const newResponseJSON = await response.json();
if(shouldCancel) return;
dispatch({type:'success',responseJSON:newResponseJSON});
} catch (newError) {
if(shouldCancel) return;
dispatch({type:'error',error:newError});
}
}
callFetch();
return () => {
shouldCancel = true
}
},[url])
return state
}
결론
간단하게 useFetch 훅을 만들어봤다. 간단한 버전과 reducer 버전 두가지 버전을 사용했으며, 결과는 똑같다.
하지만 간단한 버전은 관리해야할 상태값들이 많아 조금 복잡한 느낌이 든다.
그렇기때문에 useReducer를 사용하여 조금 더 간결하고 직관적인 코드를 만들 수 있다.