[개인프로젝트] (에러핸들링) Row Component useEffect 경고( React Hook useEffect has a missing dependency eslintreact-hooks/exhaustive-deps)

배상건·2023년 3월 21일
0

프로젝트

목록 보기
9/10

  1. 태마 별로 영화를 나열 하기 위한 Row Component를 설계한다.
    1) trending Now
    2) Top Rated
    3) Action Movies
    4) Comedy Movies
  2. 모든 Row Component 의 UI는 같으므로, 재사용 하도록 만든다.
  3. 각 Row Component에 맞는 데이터를 사용하기 위해, props 객체에 title, id, fetchURL 을 전달한다.
// src > App.js
import { Container, GlobalStyle } from "./App.styled.js";
import Banner from "./components/Banner.js";
import Nav from "./components/Nav";
import Category from "./components/Category";
import Row from "./components/Row";
import requests from "./api/requests.js";
function App() {
  return (
    <>
      <GlobalStyle />
      <Container>
        <Nav />
        <Banner />
        <Category />
        <Row 
          title="Trending Now" 
          id="TN" fetchURL={requests.fetchTrending} />
        <Row 
          title="Top Rated" 
          id="TR" fetchURL={requests.fetchTopRated} />
        <Row
          title="Action Movies"
          id="AM"
          fetchURL={requests.fetchActionMovies}
        />
        <Row
          title="Comedy Movies"
          id="CM"
          fetchURL={requests.fetchComedyMovies}
        />
      </Container>
    </>
  );
}

export default App;

문제 발생

React Hook useEffect has a missing dependency: 'fecthMovieData'. Either include it or remove the dependency array.

원인 확인

useEffect가 하는 일은 무엇일까요? useEffect Hook을 이용하여 우리는 React에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지를 말합니다. React는 우리가 넘긴 함수를 기억했다가(이 함수를 ‘effect’라고 부릅니다) DOM 업데이트를 수행한 이후에 불러낼 것입니다.

1. React에서 컴포넌트 렌더링 시 어떤 일을 수행하는가?

컴포넌트가 랜더링 될 때, 리액트는 컴포넌트 내 함수를 기억하고 DOM 없데이트를 수행 한 이후 호출하게 된다.

  • 컴포넌트 랜더링 과정을 이해하지 못했기 때문에 나타난 경고문이다.
    이는 불필요한 함수의 재생성으로써, 필요시에만 재생성 될 수 있도록 메모이제이션을 해주면 해결된다.

해결 1.

(dependency)으로 설정한다.

  1. 컴포넌트가 랜더링 될 때, fetchMovieData의 불필요한 재생성을 막기 위해, useCallbakc의 콜백함수로 fetchMovieData를 전달한다.
  2. useCallbakc 이 새로 생성되는 조건은 fetchUrl 가 변경될 때마다 생성되야 하므로, useCallbakc의 dependency 배열에 fetchUrl 를 전달한다.
  3. fetchUrl의 변경에 따라, useCallbakc 이 새로 생성되면, fetchMovieData의 값도 변경된다.
  4. fetchMovieData 의 값이 변경될 때마다, useEffect도 변경되어야 하므로, useEffect도 dependency를 fetchMovieData로 정의한다.
  • useCallbakc의
import React, { useState, useEffect, useCallback } from "react";
import { axiosInstance } from "../api/axios";
import requests from "../api/requests";
const Row = ({ title, id, fetchUrl }) => {
  const [movies, setMovies] = useState([]);
 // 2) fecthMovieData 변경 -> useEffect 호출
  useEffect(() => {
    fecthMovieData();
  }, [fecthMovieData]); /* 'fecthMovieData' was used before it 
  was defined.eslintno-use-before-define */
  
 // 1) fetchUrl 변경 -> useCallback() -> fecthMovieData 변경
  const fecthMovieData = useCallback(async () => {
    const axiosReq = await axiosInstance.get(fetchUrl);
    console.log("axiosReq", axiosReq);
    setMovies(axiosReq.data.results);
  }, [fetchUrl]);

  return <div>Row</div>;
};

export default Row;

2. 함수 표현식이 호이스팅되어 함수가 아닌, 변수로 인식 됨

  • useEffect는 컴포넌트가 랜더링 될 때, 수행하는 side-effect 라는 것을 기억해야한다.
  • 이를 이해했다면, 위 코드에서 "'fecthMovieData' was used before it was defined." 경로를 보내주는지 이해할 수 있다.
  • 위 로직은 컴포넌트가 랜더링 되고 fecthMovieData 함수를 호출하고 있다.
  • 그러나, 호이스팅의 결과로 fecthMovieData 는 함수가 아닌 변수로 인식되어, fecthMovieData 가 정의되기 전에 사용되었다고 경고하는 것이다.

해결 2.

  • 이를 해결하기 위해, 컴포넌트의 랜더링 과정에 맞게, fecthMovieData 함수를 useEffect 상단에 위치 시켜, side-effect를 가능하게 했다.
import React, { useState, useEffect, useCallback } from "react";
import { axiosInstance } from "../api/axios";
import requests from "../api/requests";
const Row = ({ title, id, fetchUrl }) => {
  const [movies, setMovies] = useState([]);

  const fecthMovieData = useCallback(async () => {
    const axiosReq = await axiosInstance.get(fetchUrl);
    console.log("axiosReq", axiosReq);
    setMovies(axiosReq.data.results);
  }, [fetchUrl]);

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

  return <div>Row</div>;
};

export default Row;
profile
목표 지향을 위해 협업하는 개발자

0개의 댓글