본문 바로가기

웹개발

React 컴포넌트 라이프사이클에 대해 알아보기

안녕하세요 devRookie 입니다. 



요즘 React에 대해서 조금씩 공부하다보니 정리해보고싶은 부분이 생겼습니다. 
오늘은 컴포넌트 라이프사이클에 대해서 포스팅 해보도록 하겠습니다. 
React 컴포넌트 라이프사이클은 크게 3가지 카테고리로 분류됩니다.


1. 마운트(Mounting) 
2. 업데이트(Updating) 
3. 언마운트(Unmounting)

 


1. 마운트(Mounting)

- constructor: 컴포넌트 생성 시 호출되는 메소드입니다. 컴포넌트의 초기 상태값을 설정할 때 사용합니다.
- render: 컴포넌트가 생성되고 렌더링될 때 호출되는 메소드입니다. 컴포넌트의 구조를 정의합니다.
- componentDidMount: 컴포넌트가 생성된 후, DOM에 마운트된 직후에 호출되는 메소드입니다. 초기화 작업이나 외부 API 호출 등의 작업을 수행할 때 사용합니다.


2. 업데이트(Updating)
- shouldComponentUpdate: 컴포넌트의 업데이트가 필요한지 결정하는 메소드입니다. 컴포넌트의 성능 최적화에 사용됩니다.
- componentWillUpdate: shouldComponentUpdate가 true를 반환한 경우, 컴포넌트를 업데이트하기 전에 호출되는 메소드입니다.
- render: 컴포넌트가 업데이트될 때마다 호출되는 메소드입니다.
- componentDidUpdate: 컴포넌트가 업데이트된 후에 호출되는 메소드입니다. DOM 업데이트 이후에 필요한 작업을 수행할 때 사용합니다.




3. 언마운트(Unmounting)
- componentWillUnmount: 컴포넌트가 DOM에서 언마운트되기 전에 호출되는 메소드입니다. 메모리 누수 리액트 라이브러리의 컴포넌트 라이프사이클에 대한 개념과 이해를 바탕으로, 컴포넌트 라이프사이클에 대한 구체적인 설명과 함께 이를 이용한 예제를 제시해주는 것이 좋을 것입니다.



## 컴포넌트 라이프사이클이란?




컴포넌트 라이프사이클은 리액트 컴포넌트가 생성될 때, 업데이트될 때, 그리고 제거될 때 일어나는 일련의 과정을 의미합니다. 이 과정에서 컴포넌트는 특정한 메소드를 자동으로 호출하며, 이를 이용하여 컴포넌트의 상태를 초기화하거나 업데이트하거나 제거할 수 있습니다.




컴포넌트 라이프사이클은 크게 세 가지 단계로 나뉘어집니다.




1. **마운트(Mount)**: 컴포넌트가 최초로 생성될 때 호출되는 단계입니다.
2. **업데이트(Update)**: 컴포넌트의 상태가 변경될 때 호출되는 단계입니다.
3. **언마운트(Unmount)**: 컴포넌트가 제거될 때 호출되는 단계입니다.




이 단계들은 다시 세부적인 메소드들로 나눌 수 있으며, 이를 이용하여 특정한 로직을 수행할 수 있습니다.




## 컴포넌트 라이프사이클 메소드




컴포넌트 라이프사이클 메소드는 크게 두 가지로 나뉩니다.




1. **클래스 컴포넌트(Class Component)에서 사용되는 메소드**



   - constructor()
   - static getDerivedStateFromProps()
   - render()
   - componentDidMount()
   - shouldComponentUpdate()
   - getSnapshotBeforeUpdate()
   - componentDidUpdate()
   - componentWillUnmount()




2. **함수형 컴포넌트(Functional Component)에서 사용되는 메소드**



   - useEffect()
   - useLayoutEffect()
   - useMemo()
   - useCallback()
   - useRef()
   - useReducer()
   - useState()




클래스 컴포넌트에서 사용되는 메소드는 컴포넌트의 상태(state)와 라이프사이클 이벤트에 따라 호출됩니다. 함수형 컴포넌트에서는 React Hooks를 이용하여 라이프사이클과 상태 관리를 할 수 있습니다.

## 컴포넌트 라이프사이클 메소드의 예제
컴포넌트 라이프사이클의 각 메소드마다 예제를 통해 설명해보겠습니다.

#### 1. constructor()

`constructor()` 메소드는 컴포넌트가 처음 만들어질 때 호출됩니다. 컴포넌트에서 사용되는 `state` 값을 초기화하거나 메소드를 바인딩하는 등의 작업을 할 수 있습니다. 아래 예제에서는 `props`를 받아와서 `state`를 초기화하고, `handleClick` 메소드를 바인딩합니다.

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Click me</button>
      </div>
    );
  }
}

export default MyComponent;


#### 2. static getDerivedStateFromProps()

`static getDerivedStateFromProps()` 메소드는 컴포넌트가 생성될 때와 
업데이트될 때 모두 호출됩니다. 이 메소드는 `props`로부터 상태값을 도출해내는 데 사용됩니다. 
이 메소드는 `render()` 메소드보다 먼저 호출되며, 반환된 값은 `state`에 업데이트됩니다.

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  static getDerivedStateFromProps(props, state) {
    return { count: props.initialCount };
  }

  render() {
    return <p>Count: {this.state.count}</p>;
  }
}

export default MyComponent;



#### 3. render()

`render()` 메소드는 컴포넌트를 렌더링할 때 호출됩니다. 이 메소드는 컴포넌트의 뷰를 반환해야 하며, 일반적으로 JSX를 사용하여 작성됩니다.

import React, { Component } from 'react';

class MyComponent extends Component {
  render() {
    return <p>Hello, world!</p>;
  }
}

export default MyComponent;



#### 4. componentDidMount()

`componentDidMount()` 메소드는 컴포넌트가 처음으로 렌더링된 후 호출됩니다. 이 메소드는 네트워크 요청을 보내거나 DOM 노드에 접근하는 등의 작업을 할 때 사용됩니다.



#### 5. shouldComponentUpdate()

**shouldComponentUpdate(nextProps, nextState)** : 컴포넌트의 props와 state가 변경되었을 때 리렌더링을 할 지 결정하는 메소드입니다. 이 메소드가 true를 반환하면 리렌더링이 되고, false를 반환하면 리렌더링이 되지 않습니다. 성능 최적화에 매우 중요한 메소드이며, 기본값은 true입니다.

javascript
class ExampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  shouldComponentUpdate(nextProps, nextState) {
    // count 값이 변경될 때만 리렌더링
    if (nextState.count !== this.state.count) {
      return true;
    }
    return false;
  }

  render() {
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me!
        </button>
      </div>
    );
  }
}



- **componentWillUpdate(nextProps, nextState)** : shouldComponentUpdate 메소드가 true를 반환했을 때, 리렌더링하기 직전에 호출되는 메소드입니다. 이 메소드에서는 setState를 호출할 수 없으며, 주로 컴포넌트가 업데이트되기 전에 해야 할 작업들을 처리합니다.

javascript
class ExampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextState.count !== this.state.count) {
      return true;
    }
    return false;
  }

  componentWillUpdate(nextProps, nextState) {
    console.log(`count 값이 ${this.state.count}에서 ${nextState.count}로 변경될 예정입니다.`);
  }

  render() {
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me!
        </button>
      </div>
    );
  }
}
```

- **componentDidUpdate(prevProps, prevState)** : 컴포넌트의 업데이트가 완료된 직후에 호출되는 메소드입니다. 이 메소드에서는 이전 props나 state와 현재 props나 state를 비교하거나, DOM 노드에 접근하여 작업을 수행할 수 있습니다.

```javascript
class ExampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextState.count !== this.state.count) {
      return true;
    }
    return false;
  }

  componentDidUpdate(prevProps, prevState) {
    console.log(`count 값이 ${prevState.count}에서 ${this.state.count}로 변경되었습니다.`);
  }

  render() {
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me!
        </button>
      </div>
    );
  }
}