axios 요청 취소

미마모코딩·2022년 10월 11일
0

axios cancel Token

목록 보기
1/1
post-thumbnail

우리는 axios로 요청을 보내는것이 익숙 할 것이다.

물론 fetch를 써서 할 수도 있지만..

오늘은 axios의 취소요청을 공부해보자.

이러한 취소요청은 왜 쓰는걸까?

이전에 포스팅한 useEffect의 클린업 함수와 관련이 있다.

const useBookSearch = (query, pageNumber) => {

//여러개의 useState들

  const [error, setError] = useState(false);
  const [loading, setLoading] = useState(false);
  const [books, setBooks] = useState([]);
  const [hasMore, setHasMore] = useState();
  
  useEffect(() => {
    setLoading(true); //데이터를 받아오기 전이니 로딩중
    setError(false); //에러도 아직 안난 상황
    let cancel; // 캔슬러
    axios               //url                   //config
      .get("http://openlibrary.org/search.json", {
        params: { q: query, page: pageNumber },
        cancelToken: new axios.CancelToken((c) => (cancel = c)),
      })      
      .then((res) => {
        setBooks((prev) => {
          return [  //중복제거 new Set    빈배열에 북타이틀 넣어주기
            ...new Set([...prev, ...res.data.docs.map((book) => book.title)]),
          ];
        });
        setHasMore(res.data.docs.length > 0);  //무한스크롤을 만들예정
        setLoading(false); //데이터 받아온 후 니까 로딩중아님
      })
      .catch((e) => {
        if (axios.isCancel(e)) return; 
      });
    return () => cancel(); //캔슬러함수
  }, [query, pageNumber]);
  return { error, loading, books, hasMore };
};

export default useBookSearch;

위 코드를 간단하게 설명하자면 에러,로딩,책의 데이터,더 보여줄지 말지 의 관한 코드의 조각들이다.

먼저 처음에 데이터를 axios를 통해 받아오고 query,pageNumber가 바뀔 때 마다 다시 호출되면서 요청을 하게된다.

import useBookSearch from "./useBookSearch";

const [query, setQuery] = useState(""); 

const [pageNumber, setPageNumber] = useState(1);

const handleSearch = (e) => {
    setQuery(e.target.value);
    setPageNumber(1);
  };
  
  useBookSearch(query, pageNumber);

<input value={query} onChange={handleSearch}></input>

위와같이 온체인지를 걸어두고 쿼리의 값을 바꾸는 작업을 진행했다.

쿼리가 하나하나 바뀔때마다 각각 계속 요청이 불필요하게 많이 갈 것이며 스테이트가 될때마다 마운트,언마운트가 계속 반복적으로 되면서 성능이 저하될것이다.

이러한 메모리 누수를 막기위해 클린업함수를 useEffect안에서 작성해주고 요청을 취소하기 위해

cancelToken을 사용하는것이다.

CancelToken 만들기

Axios 취소 토큰 API는 취소가능한 promises 제안을 기반으로 사용한다.

let cancel;
axios.get('/user/12345', {
cancelToken: new axios.CancelToken(function executor(c) {
  // excutor 함수는 cancel 함수를 매개 변수로 받습니다.
  cancel = c;
})
});
// 요청 취소
cancel();

위와같이 먼저 변수 cancel을 선언해준다.

그리고 요청안에 config부분에서
cancelToken: new.axios.CancelToken((c)=>{cancel=c}) 를해준다.
위 화살표 함수에서 매개변수로 전달받은 c가 캔슬러 함수이고
c=cancel 에 담아두었다.

그리고우리는 이 토큰을 useEffect안에서 사용하려면

return < 클린업함수의 부분

  axios
      .get("http://openlibrary.org/search.json", {
        params: { q: query, page: pageNumber },
        cancelToken: new axios.CancelToken((c) => (cancel = c)),
      })
      .then((res) => {
        setBooks((prev) => {
          return [
            ...new Set([...prev, ...res.data.docs.map((book) => book.title)]),
          ];
        });
        setHasMore(res.data.docs.length > 0);
        setLoading(false);
      })
      .catch((e) => {
        if (axios.isCancel(e)) return;
      });
    return () => cancel();
  }, [query, pageNumber]);
  return { error, loading, books, hasMore };

위코드의 캐치문에서 에러를 전달받고 에러가 있다면 즉시 종료한다.

에러가 없어서 마지막 문까지 가게되었다면 return () => cancel 캔슬러 함수를 호출해 클린업을 유도하는 것이다.

이렇게 되면 우리가 반복적으로 onChange 이벤트를 통해 컴포넌트가 마운트되고 , 언마운트 될때

클린업이 먼저 호출되기 때문에 반복적인 리랜더링을 막을 수 있다.

0개의 댓글