리액트 : useEffect

로빈·2023년 9월 5일
0

리액트에는 Side Effect라는 말이 있다.

Side Effect란?

함수의 목적인 Input을 받아서 output을 산출하는 것 이외의 모든 행위를 의미한다.

const num = 1;

const sum = (x) => {
  return x + num;
};

위에 경우는 외부요소인 num을 가져오기 때문에 side effect가 있다고 표현할 수 있다.
DOM을 조작하고, console에 특정 문자를 출력하는 행위 또한 side effect가 발생한다고 할 수 있다.

즉 정리하자면
side effect는 함수가 input을 받아서 output을 산출하는 과정에서

  • 외부의 값을 읽어오는 행위
  • 외부의 값을 변경하는 행위를 의미한다.

이러한 side effect가 있는 함수는 동작 결과를 예측하기 쉽지 않아서 주의해야 한다. 따라서 , 개발자들은 side effect를 최소화 하면서 프로그램을 설계하되, side effect가 필요한 경우에는 그것을 반드시 통제 가능하게 만들어야 한다.

Side Effect 종류 :

  • Data Fetching : 데이터 가져오기
  • DOM 접근 및 조작
  • 구독 : 변화를 계속해서 지켜보고 변화가 발생하면 특정 액션을 취하는 것



Side Effect의 문제점 :

리액트는 컴포넌트의 state나 props가 변하면 자동으로 해당 함수 컴포넌트를 다시 호출하면서 리렌더링을 수행해 준다.

하트 색깔을 변경하는 등 작은 UI 업데이트가 발생할 때마다 매번 모든 피드 데이터를 다 가져온다면 불필요한 동작을 계속 수행하기에 비효율적이다.

Side Effect는

  • 렌더링을 Blocking 하지 않기 위해서 렌더링이 모두 다 완료되고 난 후 실행할 수 있어야 한다.
  • 매 렌더링마다 실행되는 것이 아니라 내가 원할 때만 조건부로 실행할 수 있어야 한다.

리액트는 이를 useEffect라는 hook을 통해 해결한다.

useEffect 사용법:

useEffect(콜백 함수, 의존성 배열);

useEffect의 인자로 전달된 콜백 함수는 곧바로 호출되는 것이 아니라 모든 렌더링이 완료된 후에 호출된다. 의존성 배열은 바로 side effect의 발생 여부를 결정짓는 조건이다.

첫 번째 렌더링 이후에는 무조건 useEffect에 전달된 콜백 함수를 호출하고 다음 렌더링부터는 아래의 조건에 따라 동작한다.

  1. 의존성 배열이 전달되지 않았다면 매 렌더링마다 콜백 함수를 호출한다.

  2. 의존성 배열이 전달되었다면 의존성 배열의 값을 검사한다.

    • a. 의존성 배열에 있는 값 중 하나라도 이전 렌더링과 비교했을 때 달라졌다면 콜백 함수를 호출한다.

    • b. 의존성 배열에 있는 값이 이전 렌더링과 비교했을 때 모두 다 같다면 콜백 함수를 호출하지 않는다.


즉, useEffect에서 첫 번째 인자인 콜백 함수는 **실행시킬 동작**을 결정하고 두 번째 인자인 의존성 배열은 **실행시킬 타이밍을** 결정짓는다고 할 수 있다.

렌더링과 useEffect 과정

함수 컴포넌트의 렌더링과 useEffect가 발생하는 과정을 풀어서 설명하자면 아래와 같다.

  1. 컴포넌트가 렌더링 된다.

    (최초로 진행되는 렌더링은 브라우저에 처음으로 이 컴포넌트가 보였다는 의미로 mount 라고 표현한다.)

  2. useEffect 첫 번째 인자로 넘겨준 콜백 함수가 호출된다. (Side Effect)

  3. 컴포넌트의 state 또는 props가 변경되었을 경우 리렌더링이 발생한다. (update)

  4. useEffect는 두 번째 인자에 들어있는 의존성 배열을 확인한다

    • a. 만약 의존성 배열이 전달되지 않았거나 / 의존성 배열 내부의 값 중 이전 렌더링과 비교했을 때 변경된 값이 하나라도 있다면 첫 번째 인자로 넘겨준 콜백 함수가 호출된다. (Side Effect)
    • b. 의존성 배열 내부의 값 중 이전 렌더링과 비교했을 때 변경된 값이 없다면 콜백 함수를 호출하지 않는다.
    • c. state 또는 props가 변경된다면 3~4의 과정을 반복
  5. 컴포넌트가 더 이상 필요 없어지면 화면에서 사라진다.

    (컴포넌트가 브라우저의 화면에서 사라졌다는 의미로 unmount라고 표현한다.)

Clean Up Effect :

useEffect(() => {
  const countTime = () => {
    console.log('100ms가 지났습니다.');
  };

  setInterval(countTime, 100);
}, []);

위 코드와 같이, 창을 옮겼을 때도 반복되는 함수를 막기 위해 clean up이 필요하다.

useEffect(() => {
  const button = document.getElementById('consoleButton');

  const printConsole = () => {
    console.log('button clicked');
  };

  button.addEventListener('click', printConsole);

  // side effect를 clean up 하기 위한 함수를 선언한다.
  const removeEventListener = () => {
    button.removeEventListener('click', printConsole);
  };

  // clean up 함수를 return 한다.
  return removeEventListener;
});

위와 같이 return을 사용해주면 된다.
clean 합수는 두가지 경우에 호출해 준다.
1. 다음 side effect를 발생시키기 전
2. 컴포넌트가 unmount 될 때

profile
프론트엔드 개발자

0개의 댓글