Skip to content

useEffect

useEffect는 React 컴포넌트에서 사이드 이펙트를 처리하는 Hook이다.

💡 사이드 이펙트

사이드 이펙트란 컴포넌트가 화면을 렌더링하는 작업 외에, 컴포넌트의 동작에 따라 추가로 실행되는 작업을 의미한다.

라이프사이클의 특정 시점에 실행하는 작업도 사이드 이펙트로 볼 수 있다.

  • 컴포넌트가 처음 화면에 나타났을 때 콘솔 출력하기
  • 특정 state 값이 변경되었을 때 작업 실행하기
  • 서버에서 데이터 불러오기
  • 타이머 설정하기
  • 이벤트 리스너 등록하기
  • 컴포넌트가 사라질 때 정리 작업하기

useEffect 기본 문법

jsx
useEffect(() => {
  // 실행할 작업
 }, [의존성 배열]);

첫 번째 인수에는 실행할 콜백 함수를 전달하고, 두 번째 인수에는 의존성 배열을 전달한다.


jsx
// useEffect(콜백함수, [의존성 배열]);
useEffect(() => {}, [count]);

의존성 배열은 Dependency Array라고 하며, 줄여서 deps라고 부르기도 한다.
의존성 배열에 어떤 값을 넣느냐에 따라 useEffect가 실행되는 시점이 달라진다.


useEffect 실행 시점

useEffect는 의존성 배열에 따라 크게 세 가지 방식으로 실행된다.

1. 렌더링될 때마다 실행

jsx
useEffect(() => {
  console.log("렌더링될 때마다 실행");
});

이 경우 컴포넌트가 처음 렌더링될 때도 실행되고, stateprops가 변경되어 다시 렌더링될 때도 실행된다.


2. 처음 한 번만 실행

의존성 배열에 빈 배열 []을 넣으면 컴포넌트가 처음 렌더링된 후 한 번만 실행된다.

jsx
useEffect(() => {
  console.log("Mount");
}, []);

이 방식은 컴포넌트가 처음 화면에 나타나는 마운트 시점에 실행할 작업을 작성할 때 사용한다.

예를 들어 다음과 같은 작업에 사용할 수 있다.

  • 초기 데이터 요청
  • 초기 설정
  • 외부 라이브러리 초기화
  • 컴포넌트가 처음 나타났을 때 콘솔 출력

3. 특정 값이 변경될 때 실행

의존성 배열에 특정 값을 넣으면 해당 값이 변경될 때마다 실행된다.

jsx
useEffect(() => {
  console.log(`count: ${count}`);
}, [count]);

위 코드는 count 값이 변경될 때마다 실행된다.
즉, 의존성 배열에 들어간 값이 변경되면 useEffect의 콜백 함수가 다시 실행된다.


useEffect와 라이프사이클

React 컴포넌트의 라이프사이클은 크게 세 단계로 나눌 수 있다.

  • Mount → 컴포넌트가 처음 화면에 나타남
  • Update → state나 props 변경으로 다시 렌더링됨
  • Unmount → 컴포넌트가 화면에서 사라짐

함수 컴포넌트에서는 useEffect를 사용해 이 라이프사이클 흐름을 제어할 수 있다.


1. Mount 제어하기

Mount는 컴포넌트가 처음 화면에 나타나는 단계이다.

jsx
useEffect(() => {
  console.log("Mount");
}, []);

의존성 배열에 빈 배열 []을 넣었기 때문에 이 코드는 컴포넌트가 처음 렌더링된 후 한 번만 실행된다.


jsx
import { useEffect } from "react";

function App() {
  useEffect(() => {
    console.log("Mount");
  }, []);

  return <div>App</div>;
}

export default App;

이처럼 컴포넌트가 처음 나타났을 때 실행하고 싶은 작업은 빈 배열을 사용해 작성할 수 있다.


2. Update 제어하기

Update는 컴포넌트가 다시 렌더링되는 단계이다.

컴포넌트는 다음과 같은 경우 업데이트된다.

  • state가 변경될 때
  • props가 변경될 때
  • 부모 컴포넌트가 다시 렌더링될 때

의존성 배열을 생략하면 렌더링될 때마다 useEffect가 실행된다.


jsx
useEffect(() => {
  console.log("Update");
});

하지만 이 코드는 처음 마운트될 때도 실행된다.
처음 렌더링은 제외하고, 업데이트될 때만 실행하고 싶다면 useRef를 함께 사용할 수 있다.


jsx
import { useEffect, useRef, useState } from "react";

function App() {
  const [count, setCount] = useState(0);
  const isMounted = useRef(false);

  useEffect(() => {
    if (!isMounted.current) {
      isMounted.current = true;
      return;
    }

    console.log("Update");
  });

  return <button onClick={() => setCount(count + 1)}>count: {count}</button>;
}

export default App;
  • 컴포넌트가 처음 렌더링된다.
  • useEffect가 실행된다.
  • isMounted.currentfalse이므로 true로 변경하고 종료한다.
  • 이후 state가 변경되어 다시 렌더링된다.
  • 이제 isMounted.currenttrue이므로 "Update"가 출력된다.

useRef는 값이 변경되어도 컴포넌트를 다시 렌더링하지 않는다.
그래서 마운트 여부를 기억하는 용도로 사용할 수 있다.


3. Unmount 제어하기

Unmount는 컴포넌트가 화면에서 사라지는 단계이다.


jsx
useEffect(() => {
  return () => {
    console.log("Unmount");
  };
}, []);

useEffect의 콜백 함수에서 함수를 return하면, 이 함수는 클린업 함수 또는 정리 함수가 된다.
클린업 함수는 컴포넌트가 화면에서 사라질 때 실행된다.


jsx
import { useEffect } from "react";

const Even = () => {
  useEffect(() => {
    return () => {
      console.log("UnMount");
    };
  }, []);

  return <p>짝수입니다.</p>;
};

export default Even;

이 컴포넌트는 화면에 나타날 때는 <p>짝수입니다.</p>를 렌더링한다.
그리고 컴포넌트가 화면에서 사라질 때 useEffect의 정리 함수가 실행되면서 "UnMount"가 출력된다.


정리

💡 useEffect는 React 컴포넌트에서 사이드 이펙트를 처리하는 Hook이다.

컴포넌트가 렌더링된 이후 실행할 작업을 작성할 수 있고, 의존성 배열을 통해 실행 시점을 제어할 수 있다.

  • 의존성 배열 없음 → 렌더링될 때마다 실행
  • 빈 배열 [] → 처음 한 번만 실행
  • [count] → count가 변경될 때마다 실행
  • return 함수 → 컴포넌트가 사라질 때 정리 작업 실행

라이프사이클 관점에서는 다음과 같이 이해할 수 있다.

  • Mount → useEffect(() => {}, [])
  • Update → useEffect(() => {})
  • Unmount → useEffect(() => { return () => {} }, [])