인프런 커뮤니티 질문&답변

컴공과님의 프로필 이미지
컴공과

작성한 질문수

따라하며 배우는 리액트 A-Z[19버전 반영]

useEffect 관련 문의

작성

·

446

1

 

react 기능 중 useEffect 사용을 언제 해야 하는지 잘 판단이 안될때가 많습니다.

강의 듣는중에 화면 rendering과 관련된 곳에 useEffect를 사용한다고 말씀하신것 같습니다.

그럼 입력박스에 텍스트가 입력되면서 onChange 이벤트로 인해 화면 rendering이 발생하여 useEffect를 적용하고, 넷플릭스 Navigation bar의 스크롤시 화면 rendering으로 인해 window.addEventListener 를 useEffect로 감쌌다고 이해하면 맞는건지 문의 드립니다.

답변 1

0

John Ahn님의 프로필 이미지
John Ahn
지식공유자

안녕하세요 !
제가 좀 더 자세히 설명해야했는데
설명이 부족했던거 같네요!

const App = () => {
 
  useEffect(() => {
   2. 아래 UI부분이 먼저 렌더링 된 후에 여기가 호출이 됩니다. 
  }, [])
  

  return (
    <div style={{ padding: '4rem' }}>
      1. 여기가 먼저 렌더링 됩니다.
    </div>
  )
}

우선 순서가 컴포넌트 전체가 렌더링이 됩니다. 그러면 위와 같이 UI 부분이 화면에 보이게 되겠죠?
그런 후에 useEffect가 호출이 됩니다.
useEffect에서는 어떤 걸 해주면 될까요?
이 컴포넌트에서 필요한 데이터를 데이터베이스에서 가져오거나 api 요청을 할 수도 있습니다.
그래서 useEffect에서
1. 요청을 보내서 데이터를 가져온 후에
2. 가져온 데이터를 state에 setState(response)로 넣어주면
3. state가 변하기 때문에 컴포넌트가 다시 렌더링 되게 됩니다.
4. 이렇게 해서 가져온 데이터를 화면에서도 보여줄 수 있게 됩니다.

만약 useEffect에 종속성 배열에 state나 props가 들어있다면?

const App = () => {
  const [value, setValue] = useState("");
 
  useEffect(() => {
   2. 아래 UI부분이 먼저 렌더링 된 후에 여기가 호출이 됩니다. 
  }, [value])
  

  return (
    <div style={{ padding: '4rem' }}>
      1. 여기가 먼저 렌더링 됩니다.

      {value}
    </div>
  )
}

여기서 종속성 배열에 value state가 들어있습니다.
이 value 값이 "" => "a" 로 변경이 되면
useEffect에 있는 함수가 () => {} 다시 호출이 되게 됩니다.
value state가 바뀔 때마다 호출이 됩니다.



그럼 입력박스에 텍스트가 입력되면서 onChange 이벤트로 인해 화면 rendering이 발생하여 useEffect를 적용하고, 넷플릭스 Navigation bar의 스크롤시 화면 rendering으로 인해 window.addEventListener 를 useEffect로 감쌌다고 이해하면 맞는건지 문의 드립니다.

여기 질문해 주신 부분은

  useEffect(() => {
    window.addEventListener("scroll", () => {})
  
    return () => {
      window.removeEventListener("scroll", () => {});
    };
  }, []);

여기입니다.

여기는 현재 useEffect 종속성 배열에 [] 아무것도 없습니다.
그러면 컴포넌트가 시작하고 딱 한 번만
window.addEventListener("scroll", () => {})
이 부분을 호출해 준다는 말입니다.
addEventListener는 scroll 이벤트가 발생했을 때마다 이벤트 리스너 함수를 호출해 주는 것입니다.
그러기 때문에 addEventListener를 한 번만 이용해서 scroll event가 발생했을 때
계속

  if (window.scrollY > 50) {
        setShow(true);
      } else {
        setShow(false);
      }
    });

이 부분이 호출되게 됩니다.
감사합니다!




컴공과님의 프로필 이미지
컴공과
질문자

강사님!

답변 너무나 감사 드리고 이해해 도움이 많이 되었습니다.

추가적인 문의가 있어 보내드립니다.

문의1) 넷플릭스 배너이미지 만들때 함수는 매번 렌더링 될때 마다 실행된다고 하였는데

아래 함수는 왜 useEffect나 useCallback을 사용하지 않나요?

const truncate = (str, n) => {
        return str?.length > n ? str.substr(0, n - 1) + "..." : str;
      };

문의2) 위 소스에서 "str?.length"내에 ?는 어떤 의미인지 문의 드립니다.

문의3) useEffect내에 함수가 2번 호출이 됩니다. 잘못된 부분이 있을까요?

"react": "^18.2.0",
# ./api/requests.js
const requests = {
    fetchNowPlaying: 'movie/now_playing',
    fetchNetflixOriginals: '/discover/tv?with_networks=213',
    fetchTrending: '/trending/all/week',
    fetchTopRated: '/movie/top_rated',
    fetchActionMovies: '/discover/movie?with_genre=28',
    fetchComedyMovies: '/discover/movie?with_genre=35',
    fetchHorrorMovies: '/discover/movie?with_genre=27',
    fetchRomanceMovies: '/discover/movie?with_genre=1079',
    fetchDocumentaries: '/discover/movie?with_genre=99',  
};

export default requests;

# ./api/axios.js
import axios from "axios";

const instance = axios.create({
    baseURL: "https://api.themoviedb.org/3",
    params: {
        api_key: "fsdfdsfsfsafsfsdfasfdsafsd",
        language: "ko-KR"
    }
});

export default instance;
import axios from '../api/axios'
import requests from '../api/requests'
import React, { useEffect, useState } from 'react'
import './Banner.css'
import styled from "styled-components";

export default function Banner() {
    const [movie, setMovie] = useState([]);
    const [isClicked, setIsClicked] = useState(false);

    useEffect(() => {
      fetchData();
    }, []);  // 컴포넌트가 실행될때 fetchData를 호출하기 위함.

    const fetchData = async () => {
        const request = await axios.get(requests.fetchNowPlaying);
        console.log(request);

        // 여러 영화 중 영화 하나의 ID를 가져오기
        const movieId = request.data.results[
            Math.floor(Math.random() * request.data.results.length)
        ].id

        // 특정 영화의 더 상세한 정보를 가져오기
        const {data: movieDetail} = await axios.get(`movie/${movieId}`, {
            params: { append_to_response: "videos" },
        });
        setMovie(movieDetail); // result의 data 정보들을 movieDetail에 담아 저장한다.
    };

    const truncate = (str, n) => {
        return str?.length > n ? str.substr(0, n - 1) + "..." : str;
      };
.....

image

 

 

 

John Ahn님의 프로필 이미지
John Ahn
지식공유자

안녕하세요!!!

1. useCallback은 모든 함수에 사용하는 것이 아닌 주로 이것을 사용해서 유익한 것인지? 생각하고 사용하면 됩니다. 그 조건은 첫째로 이 함수를 자녀 컴포넌트에 내려 주고 있는지 두 번째로는 자녀컴포넌트에 내려준다면 자녀컴포넌트가 react memo로 감싸주고 있는지를 보면 됩니다.

useCallback을 사용하면 이것 자체로 비용이 들어가기 때문에 확실하게 사용해야 될 때 사용하는 것이 좋습니다.

2. str?. length =>? 이 것은 optional chaining으로 str이 있을 때만 length를 가져온다는 것입니다. str 이 undefined이면 undefined.length 할 수가 없죠? 그래서 에러를 방지하기 위해서? optional chaining을 이용해 줍니다!

3. 이것은 index.js 가보면 <React.StrictMode>가 있습니다.

이 부분은 개발환경에서만 작동하는데 이 부분을 지우면 한 번만 호출이 되게 됩니다 ~

감사합니다!

아 그리고 제가 답변은 잘 확인을 못해서 만약 새로운 질문이 있으면 새로운 답글로 남겨주시면 감사하겠습니다 ^^

컴공과님의 프로필 이미지
컴공과

작성한 질문수

질문하기