useEffect의 생명주기와 의존성 배열(deps)의 원리

Kingmo·2022년 4월 9일

React 컴포넌트는 브라우저 화면에 나타나고(Mount), 상태가 바뀌어 업데이트되고(Update), 화면에서 사라지는(Unmount) 일련의 생애주기를 거친다.

과거 클래스형 컴포넌트에서 사용하던 생명주기 메서드들과 현재 표준인 함수형 컴포넌트의 useEffect 훅을 1:1로 매핑하여 뭐가 다른지 봐봅시다.

클래스형 컴포넌트의 생명주기 메서드

클래스형 컴포넌트는 생애주기의 각 단계마다 브라우저가 특정 메서드를 자동으로 호출하도록 설계되어 있다.

  • render(): 컴포넌트의 JSX를 가상 DOM에 그린다.
  • componentDidMount(): 컴포넌트가 실제 DOM에 반영된 직후 1회 실행된다.
  • componentDidUpdate(prevProps, prevState): 리렌더링이 끝나고 DOM 업데이트가 완료된 후 실행된다.
  • componentWillUnmount(): 컴포넌트가 DOM에서 완전히 제거되기 직전에 실행된다.
import React, { Component } from 'react';

export default class CounterPage extends Component {
  componentDidMount() {
    console.log("마운트 완료");
  }

  componentDidUpdate() {
    console.log("업데이트 완료");
  }

  componentWillUnmount() {
    console.log("언마운트 직전");
  }

  render() {
    return <div>카운터 페이지</div>;
  }
}

함수형 컴포넌트의 생명주기: useEffect와의 1:1 매핑

함수형 컴포넌트는 별도의 메서드 대신 useEffect 훅과 의존성 배열(deps)의 조합으로 이 생명주기를 대체한다.

1. 마운트 시점 (componentDidMount)

의존성 배열에 빈 배열([])을 넘기면 최초 렌더링 이후 단 한 번만 실행된다.

useEffect(() => {
  console.log("마운트 완료");
}, []);

2. 업데이트 시점 (componentDidUpdate)

배열에 감시할 상태값을 지정하면 해당 값이 바뀔 때마다 실행된다.

useEffect(() => {
  console.log("someState 변경됨:", someState);
}, [someState]);

주의: componentDidUpdate와의 결정적 차이

  • 클래스의 componentDidUpdate는 최초 마운트 시점에는 실행되지 않고 오직 '업데이트(리렌더링)' 시점에만 호출된다.
  • 반면 useEffect(fn, [someState])는 의존성 배열에 값이 있더라도 최초 마운트 시점에 기본적으로 1회 실행된 후, 값이 바뀔 때마다 추가로 실행된다.

3. 언마운트 시점 (componentWillUnmount)

useEffect 콜백 안에서 정리(Clean-up) 함수를 return하면 컴포넌트가 화면에서 사라질 때 실행된다.

useEffect(() => {
  console.log("마운트 완료");

  // 언마운트 시 실행되는 뒷정리 함수
  return () => {
    console.log("언마운트 완료 (이벤트 리스너 해제, 타이머 정리)");
  };
}, []);

한눈에 보는 비교

생명주기 단계클래스형 컴포넌트함수형 컴포넌트 (useEffect)
마운트 (화면 등장)componentDidMount()useEffect(() => {}, [])
업데이트 (리렌더링)componentDidUpdate()useEffect(() => {}, [state]) (단, 마운트 시에도 1회 실행)
매 렌더링마다render() 직후 별도 분기useEffect(() => {}) (deps 생략)
언마운트 (화면 퇴장)componentWillUnmount()useEffect(() => { return () => {} }, [])

클래스형 컴포넌트는 생명주기 단계별로 코드가 분산되어 동일한 기능(예: 이벤트 등록과 해제)이 서로 다른 메서드로 쪼개지는 한계가 있었다.

반면 함수형 컴포넌트의 useEffect는 관련 있는 로직(구독과 구독 해제)을 하나의 블록 안에서 묶어 처리할 수 있어 코드 응집도와 가독성이 훨씬 높다.

profile
Developer

0개의 댓글