프로그래밍/ReactJS

React 개발의 핵심: 상태(State)와 생명주기(Lifecycle) 완벽 가이드 ⚛️

shimdh 2025. 9. 19. 21:09
728x90

React 애플리케이션을 개발하는 데 있어 가장 기본적이면서도 강력한 두 가지 개념은 바로 '상태(State)''생명주기(Lifecycle)' 입니다. 이 두 가지를 깊이 이해하고 효과적으로 활용하는 것은 상호작용적이고 반응적인 사용자 인터페이스(UI)를 구축하는 데 필수적입니다. 데이터가 어떻게 흐르고, 어떻게 관리되며, 시간이 지남에 따라 컴포넌트가 어떻게 변화하는지 파악하는 것은 곧 사용자 경험을 향상시키고 효율적인 코드를 작성하는 지름길이 됩니다.


1. 상태(State)의 심층 이해: UI의 동적인 변화를 위한 핵심

React에서 '상태(State)' 는 컴포넌트의 현재 상황에 대한 정보를 담고 있는 일반 JavaScript 객체입니다. 이 상태는 사용자의 액션이나 다양한 이벤트에 따라 동적으로 변화할 수 있으며, 상태의 변화는 곧 컴포넌트의 재렌더링을 유발하여 UI의 변화로 이어집니다. 이는 React가 선언적 UI를 구축하는 데 있어 핵심적인 역할을 합니다.

728x90

1.1. 상태의 역할과 작동 원리

간단한 클릭 카운터 애플리케이션을 예로 들어봅시다. 사용자가 버튼을 클릭할 때마다 화면에 표시되는 숫자가 증가해야 합니다. 이때 클릭 횟수를 저장하고 관리하는 것이 바로 '상태'의 역할입니다.

import React from 'react';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 }; // 'count'를 0으로 초기화하여 상태를 정의합니다.
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 }); // 'setState'를 사용하여 'count' 상태를 1 증가시킵니다.
  }

  render() {
    return (
      <div>
        <p>현재 카운트: {this.state.count}</p>
        <button onClick={this.increment}>증가</button>
      </div>
    );
  }
}

위 예시에서 count 변수는 컴포넌트의 상태의 한 부분으로 존재합니다. increment 메서드가 호출될 때마다 setState 함수를 통해 count의 값이 업데이트되고, 이 변화는 React가 컴포넌트를 즉시 재렌더링하여 업데이트된 카운트 값을 화면에 보여주도록 트리거합니다. 이는 사용자가 실시간으로 변화를 경험할 수 있게 합니다.

1.2. setState 사용법의 중요성: 비동기적 특성과 함수형 업데이트

setState 함수는 컴포넌트의 상태를 업데이트하는 데 필수적인 도구입니다. 이 함수는 인자로 객체 또는 함수를 받아 기존 상태와 병합함으로써 새로운 상태를 만들어냅니다. setState 사용 시 반드시 이해해야 할 중요한 특징들이 있습니다.

  • 비동기적 특성: setState 호출은 이벤트 핸들러 내에서 일괄 처리될 수 있으므로, 상태 값이 즉시 업데이트되지 않을 수 있습니다. 이는 성능 최적화를 위한 React의 내부 메커니즘입니다. 따라서 setState 호출 직후 this.state에 접근하면 예상과 다른 이전 상태 값을 얻을 수 있습니다.
  • 함수형 업데이트의 중요성: 만약 새로운 상태가 이전 상태 값에 의존한다면, setState에 함수 형태의 인자를 전달하는 것이 훨씬 안전하고 권장되는 방법입니다. 이는 동시성 업데이트 시 발생할 수 있는 문제를 방지합니다.
incrementByAmount = (amount) => {
   this.setState((prevState) => ({
     count: prevState.count + amount,
   }));
};

이 방식은 prevState를 인자로 받아 항상 최신 상태 값을 기반으로 새로운 상태를 계산하도록 보장합니다. 이는 직접 this.state에 접근하여 발생할 수 있는 잠재적인 비동기 문제를 회피하게 해줍니다.


2. 생명주기 메서드(Lifecycle Methods)의 포괄적 개요: 컴포넌트의 삶을 제어하다 🔄

React 컴포넌트는 생성(mounting), 업데이트(re-rendering), 제거(unmounting) 라는 여러 생명주기 단계를 거칩니다. 생명주기 메서드는 React가 제공하는 특별한 훅(hook)으로, 개발자가 이러한 특정 시점에 코드를 실행할 수 있도록 허용합니다. 이를 통해 컴포넌트가 화면에 나타나거나 업데이트되거나 사라질 때 특정 동작을 수행할 수 있습니다.

2.1. 주요 생명주기 메서드

  • componentDidMount: 컴포넌트가 처음으로 렌더링된 직후 호출됩니다. 이 메서드는 주로 초기 데이터 패칭, DOM 조작, 외부 라이브러리 연동, 이벤트 리스너 등록 등 컴포넌트가 마운트된 후에 필요한 작업을 수행하는 데 이상적입니다.
  • componentDidUpdate: 컴포넌트가 업데이트(재렌더링)된 직후 호출됩니다. props나 state의 변경에 반응하여 추가 작업을 수행하거나, 특정 조건에 따라 네트워크 요청을 보내는 등의 용도로 활용됩니다. 이전 props나 state와 현재 props나 state를 비교하여 불필요한 렌더링을 방지할 수 있습니다.
  • componentWillUnmount: 컴포넌트가 DOM에서 제거되기 직전에 실행됩니다. 네트워크 요청 취소, 타이머 해제, 이벤트 리스너 제거 등 컴포넌트가 제거되기 전에 필요한 정리(cleanup) 작업을 수행하기에 가장 적합한 시점입니다. 이는 메모리 누수를 방지하는 데 매우 중요합니다.

2.2. 생명주기 메서드 활용 예시

타이머 컴포넌트를 통해 생명주기 메서드의 실제 활용을 살펴보겠습니다.

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { secondsElapsed: 0 };

    this.timerID = null;
  }

  startTimer() {
    this.timerID = setInterval(() => 
      this.setState(prevState => ({ secondsElapsed: prevState.secondsElapsed + 1 })),
      1000
    );
  }

  componentDidMount() {
    this.startTimer(); // 컴포넌트가 마운트되면 타이머를 시작합니다.
  }

  componentWillUnmount() {
    clearInterval(this.timerID); // 컴포넌트가 언마운트되기 전에 타이머를 해제합니다.
  }

  render() {
    return (
      <div>경과 시간: {this.state.secondsElapsed}초</div>
    );
   }
}

이 예시에서 Timer 컴포넌트는 componentDidMount를 사용하여 컴포넌트가 화면에 나타난 직후 1초마다 secondsElapsed 상태를 증가시키는 타이머를 시작합니다. 그리고 componentWillUnmount를 통해 컴포넌트가 DOM에서 제거되기 전에 clearInterval을 호출하여 타이머를 깨끗하게 정리하고 메모리 누수를 방지합니다.


결론: 상태와 생명주기로 강력한 React 애플리케이션 구축하기

요약하자면, 상태(state) 는 컴포넌트가 동적인 데이터를 효과적으로 관리하고 UI를 업데이트할 수 있도록 해주며, 생명주기 메서드는 컴포넌트의 각 생애 주기 단계에서 일어나는 일들을 제어할 수 있는 강력한 도구를 제공합니다. 이 두 가지 핵심 개념을 함께 이해하고 적절하게 활용함으로써, 사용자 상호작용에 유연하게 반응하고 변화하는 반응형 UI를 구축할 수 있게 될 것입니다. 복잡한 애플리케이션을 개발할 때 이러한 개념을 명확히 파악하고 있다면 더욱 효율적이고 유지보수하기 쉬운 코드를 작성할 수 있습니다.

728x90