CodeLyst

[React] TypeScript에서 Custom React Hook 적용하기

#React@kkiyya
thumb nail

Custom Hook


React Hook이란?

함수 컴포넌트에서 React State와 생명주기 기능 (lifecycle features)를 연동할 수 있게 해주는 함수입니다.

class없이 React를 사용할 수 있도록 해주는 라이브러리입니다.

  • 최상위에서만 Hook을 호출해야합니다.
  • 비동기 함수를 콜백함수로 사용할 수 없습니다.
  • React 컴포넌트 함수 내에서만 Hook을 호출해야합니다.

eslint-plugin-react-hooks

https://www.npmjs.com/package/eslint-plugin-react-hook

  • hooks의 규칙들을 강제화하기 위한 플러그인
  • npx create react app을 통해서 프로젝트 셋팅을 완료한 상태라면 이미 내장되어 있는 플러그인입니다.

Built-in React hooks

기본적으로 React에서 제공해주는 hooks들은 아래와 같습니다.

  • useState
  • useEffect
  • useContext
  • useReducer
  • useRef
  • forwardRef
  • useImperativeHandle
  • useMemo
  • useCallback
  • useLayoutEffect
  • useDebugValue

이 built-in hook들은 따로 블로깅을 할 예정입니다.


Custom Hook을 사용하는 이유?

  • UX와 로직을 분리시킬 수 있습니다.
  • 다른 컴포넌트에서 중복되는 코드 로직들을 재사용 시킵니다.
  • 컴포넌트의 복잡한 로직을 숨길 수 있습니다. (보다 더 읽기 쉽게 만들어줍니다.)

Custom Hook의 규칙

  • input과 output이 있어야합니다.
  • 이름은 use 가 앞에 붙는 형식으로 작성됩니다. 예를 들어서 useForm useQuery 이런식입니다.
  • 컴포넌트 함수와는 다르게, jsx를 반환하지 않습니다.
  • 일반 함수와는 다르게, useState useEffect 와 같은 훅들을 이용해서 제작합니다.

내 프로젝트는 지금…

아래와 같은 axios.get 함수 코드들이 산더미로 쌓여있다.

로직은 다 똑같다. get, then, catch가 모두 똑같이 들어가있고, url, input과 output 타입만다르다.

//api/getInfoList.ts import axios from 'axios'; import {url} from '@env'; export const getInfoList = (idList: number[]) => { return axios .get(`${url}/list`, { params: { id_list: idList, }, }) .then(response => { return response.data; }) .catch(err => { console.error(err); }); };

이걸 Custom Hook으로 가독성도 좋고, 코드양을 획기적으로 줄일 수 있었다.


Custom Hook 적용하기


파일명 셋팅

hooks/useFecth.hook.ts로 이름을 지어주었다.


custom Hook

//hooks/useFecth.hook.ts import axios from 'axios'; import {baseUrl} from '@env'; import {useEffect, useState} from 'react'; const useFetch = <T>(url: string) => { const [response, setResponse] = useState<T[] | null>(); const [isLoading, setIsLoading] = useState<boolean>(false); const [isError, setIsError] = useState<boolean>(false); useEffect(() => { setIsLoading(true); axios .get(`${baseUrl}/${url}`) .then(res => { setIsLoading(true); setIsError(false); setResponse(res.data); }) .catch(err => { console.error(url, err); setIsLoading(false); setIsError(true); setResponse(null); }); }, [url]); return [response, isLoading, isError] as const; }; export default useFetch;
  • 응답값, 로딩상태, 에러상태를 관리해주기 위해 state hook을 사용해주었습니다.
  • then, catch 처리 상태에 따라서 해당 state에 변화를 주었습니다.

사용할 때는 아래와 같이 loading 처리만 해주면 간단하게 코드가 사용되는 것을 확인할 수 있습니다.

//pages/index.tsx const [response, isError, isLoading] = useFetch( `url`, ); if(isLoading){ return (...로딩중일 때 띄울 것...) } return (...로딩이 끝났을 때 띄울 것...)

Custom Hook 사용해보니 더 좋은 점

로딩 처리가 쉬워졌습니다.

원래 custom hook을 사용하지 않고 data를 get을 해올때는, 로딩 state을 해당 로직이 사용되는 UX에다가 넣어줘야 했었습니다.

만약 한 페이지에 axios.get이 여러개면, 그 개수만큼 state를 만들어 주었어야 했습니다.

그런걸 그냥 hook하나에서 loading값을 불러오면 되는 로직으로 수정되어 코드짜는데 용이해졌습니다.


reference

https://www.bezkoder.com/react-custom-hook-typescript/

https://ko.legacy.reactjs.org/docs/hooks-intro.html

https://defineall.tistory.com/900

https://javascript.plainenglish.io/how-to-create-a-reusable-custom-hook-with-react-js-and-typescript-6e5ef8340e1