Front-end/Javascript

[React] Component Lifecycle: 컴포넌트의 생명주기! 🎢

xeunnie 2024. 12. 4. 01:00
728x90
반응형

Component Lifecycle 톺아보기 🎢

리액트에서 컴포넌트는 생명주기(Lifecycle)를 가집니다. 컴포넌트는 태어나고(Mounting), 살아가며(Update), 마침내 떠나죠(Unmounting). 리액트의 라이프사이클 메서드와 훅을 이해하면, 컴포넌트의 상태 변화와 동작을 제어할 수 있습니다. 리액트 개발자라면 반드시 이해해야 하는 개념! 함께 시작해볼까요? 🚀


리액트 라이프사이클, 왜 중요할까? 🤔

리액트 컴포넌트는 여러 단계에서 특정 작업을 수행할 기회를 제공합니다. 예를 들어:

  • 컴포넌트가 화면에 나타날 때 데이터를 로드하거나,
  • 상태가 변경될 때 DOM을 업데이트하거나,
  • 컴포넌트가 사라질 때 리소스를 정리할 수 있죠

이 과정은 크게 세 단계로 나뉩니다:

  1. 마운트(Mounting): 컴포넌트가 DOM에 삽입될 때
  2. 업데이트(Updating): 컴포넌트의 상태(state)나 props가 변경될 때
  3. 언마운트(Unmounting): 컴포넌트가 DOM에서 제거될 때

클래스형 컴포넌트와 라이프사이클 메서드 🏛️

리액트에서는 클래스형 컴포넌트가 라이프사이클 메서드를 통해 생명주기를 제어할 수 있습니다.

 

1. 마운트(Mounting) 단계

컴포넌트가 DOM에 추가되는 과정입니다. 이 과정에서 호출되는 주요 메서드는 다음과 같습니다:

  • constructor: 컴포넌트를 초기화하는 데 사용
  • static getDerivedStateFromProps: props로부터 state를 동기화하고 싶을 때 사용
  • render: JSX를 반환하며, 컴포넌트를 화면에 렌더링
  • componentDidMount: DOM이 생성되고 나서 호출
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { data: null };
    console.log("1. Constructor: 컴포넌트 초기화");
  }

  static getDerivedStateFromProps(props, state) {
    console.log("2. getDerivedStateFromProps: props로 state 설정");
    return null; // 기본적으로 state를 변경하지 않을 때 null 반환
  }

  componentDidMount() {
    console.log("4. componentDidMount: DOM이 준비된 후 호출");
    // API 호출 예시
    fetch("https://api.example.com/data")
      .then((response) => response.json())
      .then((data) => this.setState({ data }));
  }

  render() {
    console.log("3. Render: JSX 반환");
    return <div>My Component</div>;
  }
}

 

2. 업데이트(Updating) 단계

컴포넌트의 props 또는 state가 변경될 때 실행됩니다. 이 과정에서 호출되는 주요 메서드는 다음과 같습니다:

  • static getDerivedStateFromProps: 마운트와 업데이트 모두 호출
  • shouldComponentUpdate: 리렌더링 여부를 결정
  • render: 변경된 내용을 기반으로 JSX를 반환
  • getSnapshotBeforeUpdate: DOM 업데이트 직전 상태를 캡처할 때 사용
  • componentDidUpdate: DOM 업데이트 후 호출
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log("1. shouldComponentUpdate: 리렌더링 여부 결정");
    return nextState.count !== this.state.count; // count가 변경될 때만 렌더링
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log("2. getSnapshotBeforeUpdate: DOM 변경 전 캡처");
    return { prevCount: prevState.count };
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log("3. componentDidUpdate: DOM 변경 후 호출");
    console.log("이전 count:", snapshot.prevCount);
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment
        </button>
      </div>
    );
  }
}

 

3. 언마운트(Unmounting) 단계

컴포넌트가 DOM에서 제거되는 과정입니다.

  • componentWillUnmount: 컴포넌트가 DOM에서 제거되기 직전에 호출
class MyComponent extends React.Component {
  componentWillUnmount() {
    console.log("componentWillUnmount: 컴포넌트가 제거됩니다.");
    // 예: 타이머 정리
    clearInterval(this.timer);
  }

  render() {
    return <div>Goodbye, World!</div>;
  }
}

함수형 컴포넌트와 훅(Hooks) 🪝

React Hooks가 등장하면서, 함수형 컴포넌트에서도 라이프사이클을 제어할 수 있게 되었습니다. 주요 훅은 다음과 같습니다:

  • useState: 상태 관리
  • useEffect: 사이드 이펙트를 처리
  • useRef: DOM 요소나 값 참조

useEffect로 라이프사이클 관리하기

import React, { useState, useEffect } from "react";

function MyComponent() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log("Component Mounted or Updated!");
    // Cleanup 함수 (언마운트 시 실행)
    return () => {
      console.log("Component Unmounted!");
    };
  }, [count]); // count가 변경될 때마다 실행

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

리액트의 라이프사이클 정리 🗂️

단계 클래스형 메서드 함수형 훅 설명
마운트 constructor 초기값 설정 컴포넌트 초기화
getDerivedStateFromProps 없음 props로 state를 동기화
render JSX 반환 UI 렌더링
componentDidMount useEffect DOM 생성 후 작업
업데이트 getDerivedStateFromProps 없음 props로 state를 동기화
shouldComponentUpdate 없음 리렌더링 여부 결정
render JSX 반환 UI 렌더링
getSnapshotBeforeUpdate 없음 DOM 변경 전 캡처
componentDidUpdate useEffect DOM 변경 후 작업
언마운트 componentWillUnmount useEffect 컴포넌트 제거 직전 작업

실전 예제: 데이터 가져오기와 정리하기 🛠️

아래는 API 호출과 데이터 정리를 포함한 컴포넌트 라이프사이클 관리 예제입니다.

import React, { useState, useEffect } from "react";

function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch("https://jsonplaceholder.typicode.com/users");
      const data = await response.json();
      setUsers(data);
      setLoading(false);
    }
    fetchData();
    // Cleanup: 예시로 타이머 정리 추가
    return () => {
      console.log("Cleanup on unmount");
    };
  }, []);
  if (loading) {
    return <p>Loading...</p>;
  }
  
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

마무리: 리액트 라이프사이클 완벽 이해 🎉

리액트의 라이프사이클은 컴포넌트의 상태와 동작을 관리하는 데 매우 중요합니다. 클래스형 메서드와 훅을 상황에 맞게 활용하면, 성능 최적화와 깔끔한 코드 유지가 가능합니다.

이제 리액트 컴포넌트의 “삶과 죽음”을 지휘할 준비가 되셨나용?

 

🌷전설의 개발자가 되어봅시당! 🌷

728x90
반응형