My Boundary As Much As I Experienced

클래스 컴포넌트와 라이프사이클 본문

FrontEnd/React

클래스 컴포넌트와 라이프사이클

Bumang 2024. 4. 13. 19:18

클래스 컴포넌트란?

클래스 컴포넌트는 React에서 사용되는 컴포넌트의 한 종류이다.

이전에는 주로 클래스 컴포넌트가 주류였지만, 최근에는 함수형 컴포넌트와 훅을 이용한 상태 관리가 더욱 표준적으로 쓰인다.

 

클래스 컴포넌트는 render() 메서드를 포함하여 여러 생명주기 메서드를 사용할 수 있다는 특징이 있다.

(임의로 메서드를 추가하는 것도 가능하다.) 함수형 컴포넌트에서는 hook로 이런 주기를 조작할 수 있으나 그 자유도는 클래스형보다 낮다.

 

클래스 컴포넌트의 특징

- React.Component 클래스를 상속받아서(extends하여) 정의된다.

- render() 메소드로 view로직을 처리함

- 생명주기 메서드를 사용할 수 있음

 

라이프 사이클 메서드의 분류

라이프사이클 메서드의 종류는 총 9가지이지만 크게 마운트, 업데이트, 언마운트로 3가지 카테고리로 나뉜다.

 

1. 마운트

DOM이 생성되고 웹 브라우저 상에 나타나는 것을 마운트(mount)라고 한다. 이때 호출되는 메서드는 다음과 같다.

(컴포넌트 생성)
⇒ constructor (컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드)
⇒ getDerivedFromProps (props에 있는 값을 state에 넣을 때 사용하는 메서드)
⇒ render (UI를 실제 렌더하는 메서드)
⇒ componentDidMount (컴포넌트가 웹 브라우저에 나타난 후 호출하는 메서드)

 

2. 업데이트

컴포넌트는 다음과 같은 총 네 가지 경우에 업데이트 한다.

1. props가 바뀔 때

2. state가 바뀔 때

3. 부모 컴포넌트가 리렌더링될 때

4. this.forceUpdate가 강제로 렌더링을 트리거할 때

(props 변경, state 변경, 부모 컴포넌트 리렌더링) // 업데이트를 발생시키는 요인
⇒ getDerivedFromProps (컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드, 업데이트 될때도 실행된다.)
⇒ shouldComponentUpdate (props에 있는 값을 state에 넣을 때 사용하는 메서드)

⇒ true 반환 시 render, false 반환 시 여기서 작업 취소

⇒ render (<= forceUpdate가 영향을 줄 수 있음)
⇒ getSnapshotBeforeUpdate (컴포넌트의 변화를 DOM에 반영하기 바로 직전에 호출하는 메서드. 말그대로 업데이트 전 상태를 기록해둔다.)

⇒ 웹 브라우저 상의 실제 DOM 변화

⇒ componentDidUpdate (컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드)

 

3. 언마운트

컴포넌트를 DOM에서 제거하는 것을 언마운트(unmount)라고 한다.

언마운트 하기
⇒ componentWillUnmount (컴포넌트가 웹 브라우저 상에서 사라지기 전에 호출하는 메서드입니다.)

 

종합 예시

import { Component } from "react";

class MyComponent extends Component {
	// state를 사용하려면 constructor를 써야한다.
	constructor (props) { // constructor부분을 모두 생략할 수 있지만, 만약 생략 안 한다면 props를 받아 super에 props를 제공해주는 것을 꼭 해줘야한다.
		super(props) // React.Component의 모든 설정을 계승 받기
		this.state = { // state를 쓰려면 이렇게 this바인딩을 해줘야 한다.
			city: "Chicago",
		}
		this.handleClick = this.handleClick.bind(this) // handleClick메서드의 this를 이 컴포넌트에 바인딩해서 쓰려면..
	}
	
	componentDidMount() { // 컴포넌트가 마운트될 때 1회 발생 (재렌더 영향 x)
	 ...
	}
	
	componentDidUpdate() { // 컴포넌트가 재렌더링될 때 발생
	 ...
	}
	
	handleClick() { // 
	 ...
	}

  render () {
	  const { name } = this.props
	  const { city } = this.state // constructor에서 생성
	  
	  return (
		  <div>
			  <h1>Hello, there {name}</h1>
			  <p>{city}</p>
			  <button onClick={()=>this.setState({city: "Boston"})}></button>
		  </div>
	  )
  }
}

export default MyComponent

 

클래스 컴포넌트 라이프 사이클을 종합해서 보자면?

전체 생애주기

contructor 실행

⇒ getDerivedFromProps

⇒ render (렌더)

⇒ ref (처음 마운트 될때만 찾아지고, 재렌더 시엔 다시 업데이트하지 않는다)

⇒ componentDidMount (마운트가 된 시점에만 업데이트된다. 'useEffect + 빈 의존성 배열'과 비슷)

⇒ (setState/props 바뀔 때) componentDidUpdate (업데이트될때만 실행된다)

⇒ componentWillUnmount (unmount될 때 실행된다)

⇒ 소멸

 

업데이트 시

⇒ getDerivedStateFromProps

⇒ shouldComponentUpdate (선택, 재렌더 되어야 하는지 여부)

⇒ render

⇒ getSnapshotBeforeUpdate

⇒ componentDidUpdate

 

언마운트 시

⇒ componentWillUnmount

 

 

Error Handling(에러 처리):

  • static getDerivedStateFromError(): 하위 컴포넌트의 렌더링 과정에서 에러가 발생했을 때 호출됩니다. 에러 상태를 설정하는 역할을 합니다.
  • componentDidCatch(): 하위 컴포넌트에서 발생한 에러를 처리합니다.

 

지금 클래스형 컴포넌트를 이해해서 뭐가 좋은가?

아직도 일부 라이브러리의 컴포넌트들은 함수 컴포넌트로는 잡아내기 어려운 타이밍에 특정한 조작을 하기위해 클래스형 컴포넌트를 사용한다.

 

ex) 에러바운더리: componentDidCatch나 getDerivedStateFromError 시점을 포착하기 위해 클래스형 컴포넌트를 씀

ex) Framer-motion의 exit 애니메이션: unmount시 보여줄 애니메이션을 재생하기 위해서 클래스형 컴포넌트로 구현되어 있음

 

 

 

참고자료:

제로초 리액트 웹게임 만들기 - 컴포넌트 라이플 사이클 설명 파트

리액트를 다루는 기술(김민준 저) - 7.2 라이프사이클 메서드 알아보기