HooneyLog

useFetch 커스텀 훅 만들기 (feat : reducer )

프로필 이미지

Seunghoon Shin

2022년 8월 29일 11:11

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를 사용하여 조금 더 간결하고 직관적인 코드를 만들 수 있다.