서버에서 Fetch한 데이터를 상태값에 넣어 트랙킹하고, 로딩과 에러 상태까지 관리하여 사용하는 유용한 훅이다.
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 } }
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를 사용하여 조금 더 간결하고 직관적인 코드를 만들 수 있다.