데이터 가져오기 전까지 로딩 띄우는 useLoading 커스텀 훅 만들기 (TypeScript)

ain·2023년 5월 21일
1

React

목록 보기
3/3
post-thumbnail

데이터를 가져올 때 로딩을 띄우고 싶다면 React Hook의 useState를 활용해서 사용할 수 있다.

로딩 상태값을 만들어서 데이터를 가져오기전까지 로딩을 띄우고, 다 가져왔으면 로딩을 없애주는 로직을 useState 훅을 사용하여 많이 사용해 왔을 것이다.

const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);

useEffect(() => {
  setLoading(true);
  setError(undefined);
  fetch(`...`)
    .then((res) => res.json())
    .then((data) => {
      setData(data);
    })
    .catch((error) => {
      console.error(error);
    })
    .finally(() => setLoading(false));
}, [...]);

하지만 가져와야 하는 데이터가 많다면 똑같은 로직을 여러개 만들어야 한다. 데이터를 인자로 전달하여 isLoadingdata를 반환하는 커스텀 훅을 만들어 보았다.

⏳ isLoading 만들기

// ./src/hooks/useLoading.ts
const useLoading = () => {
 const [isLoading, setIsLoading] = useState(false);
}

1. useLoading 네이밍

커스텀 훅이니 네이밍을 할 때 앞에 use를 붙여서 hooks 폴더 안에 만들어준다.
그리고 최상단에 로딩을 띄울 상태값 isLoading을 false로 초기값을 설정하여 만들어준다.

2. isLoading

이 상태값은 데이터를 받아왔는지 여부에 따라서 true, false가 변경된다(값이 변경되는 부분은 아래에서 다룰 예정이다). isLoading이 true라면 로딩 아이콘을 랜더링 하며, false라면 받아온 데이터를 뿌려준다.

📩 콜백함수 받아오기

// ./src/hooks/useLoading.ts
const useLoading = (action: (...args: ArgumentType) => Promise<T>) => {
 const [isLoading, setIsLoading] = useState(false);
}

1. 콜백함수 action

action은 인자로 받아오는 콜백함수로 데이터를 처리하는 함수를 받는다. 이 콜백함수는 데이터를 가져와서 상태 값에 저장한 함수를 말한다. 예를 들면 이런 함수다.

const handleGetTodoList = async() => {
  const data = await getTodoList();
  setData(data || [])
}

이렇게 데이터를 가져오고 처리하는 함수를 useLoading 커스텀 훅에 전달해준다.

2. Generic Type

콜백함수 action의 반환 값은 사용하는 곳마다 다른 타입을 받아올 수 있도록 하기 위해서 Generic을 사용해준다.

const [...] = useLoading<void>(...)

이렇게 useLoading을 사용하는 곳에서 void 타입을 전달해주면 useLoading의 제너릭을 사용한 곳에 void가 들어간다고 볼 수 있다:

const useLoading = (action: (...args: ArgumentType) => Promise<void>) => {
 const [isLoading, setIsLoading] = useState(false);
}

💭 데이터를 처리할 함수 만들기: handleData

데이터를 호출 하기 전후로 로딩을 처리할 handleData 함수를 만들어준다.

const handleData = async (...args: ArgumentType) => {
    setIsLoading(true);
    return await action(...args).finally(() => setIsLoading(false));
  };

1. ...args

handleData 함수안에서 인자로 받아온 콜백함수 action을 호출하기 때문에 (useLoading에서 받아온 인자 action의 모든 인자) args를 똑같이 전개연산자로 넣어준다. 그런 다음 콜백함수 action을 호출하는 부분에서 args를 전달해준다.

2. setLoading

useLoading 훅의 하이라이트이다. 로딩을 띄우고 데이터를 받아오는 일을 이 함수가 수행한다. 아래 단계를 거친다.

  • false였던 값을 true로 바꿔줌으로써 데이터를 받아오기 전까지 로딩을 띄워준다.
  • 콜백함수 action을 호출하여 데이터를 받아온다.
  • 마지막으로, 데이터를 받아오는 action이 잘 수행이 됐다면 로딩 대신 데이터를 띄워주도록 isLoading을 false로 바꾸어준다.

✅ isLoading과 handleData 반환!

마지막으로 여러 곳에서 사용할 수 있도록 isLoading과 handleData를 반환해준다. handleData를 반환해주는 이유는 사용자의 인터렉션으로 form이 제출 됐다던가, 어떤 버튼을 클릭했을 때 handleData로 데이터를 요청하고 받기위함이다.

...
return [isLoading, handleData];

💡 전체코드

import { useState } from 'react';

type UseLoadingReturnType<T> = [boolean, (...args: any[]) => Promise<T>];

const useLoading = <T>(
  action: (...args: any[]) => Promise<T>
): UseLoadingReturnType<T> => {
  const [isLoading, setIsLoading] = useState(false);

  const handleData = async (...args: any[]) => {
    setIsLoading(true);
    return await action(...args).finally(() => setIsLoading(false));
  };

  return [isLoading, handleData];
};

export default useLoading;

✨ 사용은 어떻게?

useLoading을 다시 한번 설명하자면, 데이터를 받아오기 전까지 로딩을 띄우고 데이터를 성공적으로 받아오면 데이터를 뿌리는 커스텀 훅이다.

그래서 우리가 useLoading에서 사용할 수 있는 값은 데이터를 받아오는지 모니터링 하면서 로딩을 결정하는 Boolean 값 isLoading, 그리고 사용자 인터렉션이 있을 때 데이터를 가져오는 handleData 함수, 이 두개다.

Todo 리스트를 추가한다고 치자.

// Todo.tsx
const [isLoading, createTodoLists] = useLoading(handleCreateTodos);

const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
  e.preventDefault();
  createTodos(inputText, setTodos);
}

return (
  <>
  {isLoading ? <Spinner /> : <TodoData />}
  </>
);

이런 식으로 사용할 수 있겠다.

만약 로딩 로직을 커스텀 훅으로 빼지 않았다면 handleSubmit 함수안에 setLoadinghandleCreate() 등 로딩과 데이터를 처리하는 코드들이 뭉쳐있어 가독성이 떨어질 수 있다.


마무리

useLoading은 로딩만 처리하는 커스텀 훅으로 단순하게 만들수도 있겠지만 로딩만 처리하기엔 useState로 쓰는 것과 코드 상의 차이가 없다고 느껴졌다. 그래서 주로 데이터를 받아올 때 만들어지는 것을 보고 데이터 로딩 훅을 만들어봤다.
실제로 CRUD 같은 하나 이상의 요청을 각각 받아와야 할 때, 로딩을 4곳에서 4번을 만드는 게 아닌 useLoading 훅을 사용하면 코드가 훨씬 간결해진다.

이상으로, useLoading 커스텀 훅에 대한 소개 및 사용법을 정리해보았다.

참고

profile
프론트엔드 개발 연습장 ✏️ 📗

0개의 댓글