[React] HTTP 요청에 useEffect() 사용하여 데이터 적절한 때에 패치하기

summereuna🐥·2023년 5월 21일
0

React JS

목록 보기
56/69

HTTP 요청에 useEffect() 사용하여 데이터 패치하기


대부분의 앱에서는 특정 컴포넌트가 로딩되자마자 데이터를 가져오기도 한다. 가령 사용자가 페이지를 방문하자마자 데이터를 가져오기도 한다.

💬 현재 패치 버튼을 누르는 것에 맞춰 데이터를 패치하고 있는데, 버튼을 클릭할 때 뿐만 아니라 화면이 처음 렌더링될 때에도 데이터를 즉시 패치하려면 어떻게 하면될까?

  • 바로 useEffect()를 사용하면 된다. HTTP 요청 전송은 일종의 사이드 이펙트로, 컴포넌트의 상태를 바꾸기 때문이다.

  • 메인 컴포넌트 함수 내에서 호출하지만 않는다면, 함수를 사이드 이펙트로 넣어도 된다.

  • 그런데 만약, 메인 컴포넌트의 함수 일부분으로 호출되는 함수를 사이드 이펙트로 넣어버리면 어떻게될까?
    함수가 호출되는 순간, 상태 업데이트가 발생하고, 컴포넌트 함수가 재평가 및 재렌더링되면서 함수가 다시 호출되는 무한루프가 발생하여 문제가 발생한다.

useEffect로 HTTP 데이터 패치하기

이를 피하기 위해 useEffect()를 사용한다. useEffect()는 컴포넌트가 렌더링되는 주기 안에서 사용되어야 하는 코드가 있을 때 유용하다. 컴포넌트가 재렌더링 될 경우는 좀 다르지만 말이다.

✅ useEffect()에 사이드 이펙트로 fetchMoviesHandler 함수 호출하기

useEffect(() => {
  fetchMoviesHandler();
}, []);

사이드 이펙트로 fetchMoviesHandler함수를 추가하고 두번째 인자로 디펜던시 배열를 작성하지 않으면, 패치 버튼을 클릭해도 fetchMoviesHandler 함수가 호출되지만, 동시에 컴포넌트 재평가가 발생할 때도 fetchMoviesHandler 함수가 호출된다.
그걸 막으려면 두 번째 인자로 빈 디펜던시 배열을 주면 된다.

그런데 모든 의존성은 의존성 배열에 표시해 두는 것이 좋다고 배웠는데, fetchMoviesHandler를 의존성으로 의존성 배열에 넣어야 하지 않을까?
그런데 그렇게 하면 fetchMoviesHandler가 함수이고 객체이기 때문에 컴포넌트가 재렌더링 될 때 마다 함수 역시 재생성되버린다..^^!
그러면 계~~속 재생성되니까 무한 루프가 발생해 버린다.

처음 방법 처럼 의존성 배열에 의존성으로 추가하지 않는 것이 한 방법이지만, 함수가 외부 상태를 사용한다면 의도치 않은 🐜버그가 발생할 수도 있다.

✅ 무한루프/의도치 않은 버그 발생을 대비한 해결책: useCallback

따라서 가장 좋은 해결책은 useCallback 훅을 사용하여 fetchMoviesHandler 함수를 감싸는 것이다.

  • 이제 fetchMoviesHandler 함수 안에 있는 모든 의존성을 의존성 배열에 나열해 보자.
    • 그런데 이 함수에는 외부 의존성은 없다.
    • fetch API는 글로벌 브라우저 API인데, 이는 의존성이 아니다.
    • 상태 업데이트 함수도 리액트가 절대 변하지 않을 것을 보장하므로 의존성으로 추가할 필요가 없다.
      따라서 특별히 의존성으로 추가할 것이 없다.
// useCallback으로 fetchMoviesHandler 함수 감싸기
// async 예약어는 함수 앞에 넣어 주면 된다.
const fetchMoviesHandler = useCallback(async () => {
    setIsLoading(true);
    setError(null);

    try {
      const response = await fetch("https://swapi.dev/api/films/");
      
      if (!response.ok) {
        throw new Error("Something went wrong!");
      }

      const data = await response.json();

      const transformedMovies = data.results.map((movieData) => {
        return {
          id: movieData.episode_id,
          title: movieData.title,
          openingText: movieData.opening_crawl,
          releaseDate: movieData.release_date,
        };
      });
      setMovies(transformedMovies);
    } catch (error) {
      setError(error.message);
    }

    setIsLoading(false);
  //의존성배열에 넣을 것이 없으므로 비워두면 된다.
  }, []);


//HTTP 요청 사이드 이펙트
useEffect(() => {
  fetchMoviesHandler();
}, [fetchMoviesHandler]);
//의존성 배열에 모든 의존성을 넣어줘야 하므로 fetchMoviesHandler 함수도 넣는다.

이렇게 하면 무한루프에는 빠지지 않으면서도, 처음 화면이 렌더링될 때 데이터가 자동으로 패치되고, 버튼을 클릭할 때도 데이터를 패치할 수 있다.

profile
Always have hope🍀 & constant passion🔥

0개의 댓글