본문 바로가기
FrontEnd/React.js

[React.js] React Component 생명주기 1 - Mounting

by 푸고배 2021. 2. 2.

리액트의 모든 Component는 여러 종류의 "생명주기 메서드"를 가지며, 이 메서드를 오버라이딩하여 특정 시점에 코드가 실행되도록 설정이 가능하다. 컴포넌트의 생명주기는 아래와 같다.

 

 컴포넌트 생명주기 

 Mounting 

 

아래 매서드들은 컴포넌트의 인스턴스가 생성되어 DOM 상에 삽입될 때 순서대로 호출된다.

 

1. constructor()

 constructor(props)

 

매서드를 바인딩하거나 state를 초기화하는 작업이 없다면, 해당 React 컴포넌트에는 생성자를 구현하지 않아도 된다.

 

React 컴포넌트의 생성자는 해당 컴포넌트가 마운트되기 전에 호출된다.

React.Component를 상속한 컴포넌트의 생성자를 구현할 때에는 다른 구문에 앞서 super(props)를 호출해야 한다. 그렇지 않으면 this.props가 생성자 내에서 정의되지 않아 버그로 이어질 수 있다.

 

React에서 생성자는 보통 아래의 두 가지 목적을 위해 사용한다.

constructor() 내부에서 setState()를 호출하면 안된다. 컴포넌트에 지역 state가 필요하다면 생성자 내에서 this.state에 초기 state값을 할당하면된다.

 

생성자는 this.state를 직접 할당할 수 있는 유일한 곳으로 그 외의 메서드에서는 할당을 위해 this.setState()를 사용한다.

 

constructor(props) {
  super(props);
  // 여기서 this.setState()를 호출하면 안된다.
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}

handleClick(num) = {
  // 이런 식으로 state 초기화
  this.setState({
  	counter : num
  })
}

 

생성자 내에서는 부수 효과를 발생시키거나 구독 작업(subscription)을 수행하면 안된다. 해당 경우에는 componentDidMount()를 대신 사용한다.

 

주의

state에 props를 복사하면 안된다.(아래 예제의 color props의 값이 변하더라도 state에 반영되지 않는 버그 발생)

Props의 갱신을 의도적으로 무시해야 하는 경우 props를 복사하는 패턴을 사용하면된다.

이 경우, 해당 props의 이름을 initialColor 또는 defaultColor 등으로 변경하는 편이 자연스럽다. 그러면 이후 필요에 따라 컴포넌트가 key를 변경하여 초기 state를 “재설정”하도록 강제할 수 있다.

props의 값에 의존하는 state가 필요할 때 어떻게 해야 하는지에 대하여 알고 싶다면,  state로부터 값을 가져오지 않는 법에 대한 블로그 글을 참고한다.

constructor(props) {
 super(props);
 // X
 this.state = { color: props.color };
 // O
 this.state = this.props.color;
}

 

2. static getDerivedStateFromProps()

 static getDerivedStateFromProps(props, state)

 

getDerivedStateFromProps는 최초 마운트 시와 갱신 시 모두에서 render 메서드 호출 직전에 호출된다. state를 갱신하기 위한 객체를 반환하거나, null을 반환하여 아무 것도 갱신하지 않을 수 있다.

 

이 메서드는 시간이 흐름에 다라 변하는 props에 state가 의존하는  아주 드문 사용례를 위하여 존재한다. 예를 들어, 무엇을 움직이도록 만들지 결정하기 위해 이전과 현재의 자식 엘리먼트를 비교하는 <Transition>과 같은 컴포넌트를 구현할 때 편리하게 사용할 수 있다.

 

state를 끌어오면 코드가 장황해지고, 이로 인해 컴포넌트를 이해하기 어려워진다. 보다 간단한 다른 대안들에 익숙해지는 것을 권장한다.

이 메서드는 컴포넌트 인스턴스에 접근할 수 없다. 인스턴스 접근이 필요하다면, class 정의 외부에서 컴포넌트의 props와 state에 대한 순수 함수를 추출하여 getDerivedStateFromProps()와 다른 클래스 메서드 간에 코드를 공유 및 재사용할 수 있다.

 

이 메서드는 이유와 상관없이 랜더링 때마다 매번 실행되므로 주의가 필요하다. 이는UNSAFE_componentWillReceiveProps와는 다른데, 이 메서드의 경우 부모 컴포넌트가 다시 렌더링을 발생시켰을 때에만 실행되고, 해당 컴포넌트 내에서 지역적인 setState가 발생한 경우에는 실행되지 않는다.

 

3. render()

 render()

 

render() 메서드는 클래스 컴포넌트에서 반드시 구현돼야하는 유일한 메서드이다.

이 메서드가 호출되면 this.props와 this.state의 값을 활용하여 아래의 것 중 하나를 반환해야 한다.

 

  • React 엘리먼트. 보통 JSX를 사용하여 생성된다. 예를 들어, <div />와 <MyComponent />는 React가 DOM 노드 또는 사용자가 정의한 컴포넌트를 만들도록 지시하는 React 엘리먼트이다.
  • 배열과 Fragment. render()를 통하여 여러 개의 엘리먼트를 반환한다. 자세한 정보는 Fragments 문서를 통하여 확인할 수 있습니다.
  • Portal. 별도의 DOM 하위 트리에 자식 엘리먼트를 렌더링한다. 자세한 정보는 Portals에서 확인할 수 있다.
  • 문자열과 숫자. 이 값들은 DOM 상에 텍스트 노드로서 렌더링된다.
  • Boolean 또는 null. 아무것도 렌더링하지 않는다. (대부분의 경우 return test && <Child /> 패턴을 지원하는 데에 사용되며, 여기서 test는 boolean 값이다.)

render() 함수는 순수해야 한다. 즉, 컴포넌트의 state를 변경하지 않고, 호출될 때마다 동일한 결과를 반환해야 하며, 브라우저와 직접적으로 상호작용을 하지 않는다.

브라우저와 상호작용하는 작업이 필요하다면, 해당 작업을 componentDidMount()이나 다른 생명주기 메서드 내에서 수행한다. render()를 순수하게 유지하여야 컴포넌트의 동작을 이해하기 쉽다.

 

주의

shouldComponentUpdate()가 false를 반환하면 render()는 호출되지 않는다.

 

4. componentDidMount()

 componentDidMount()

 

componentDidMount()는 컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출된다. DOM 노드가 있어야 하는 초기화 작업은 이 메서드에서 하면된다. 외부에서 데이터를 불러와야 하는 경우, 네트워크 요청을 보내기 적절한 위치이다.

 

이 메서드는 데이터 구독을 설정하기 좋다. 데이터 구독이 이루어졌다면, componentWillUnmount()에서 구독 해제 작업을 반드시 수행해야한다.

 

componentDidMount()에서 즉시 setState()를 호출하는 경우도 있다. 이로 인해 추가적인 렌더링이 발생하지만, 브라우저가 화면을 갱신하기 전에 작업이 가능하다. 이 경우 render()가 두 번 호출되지만, 사용자는 그 중간 과정을 볼 수 없다. 이런 사용 방식은 성능 문제로 이어지기 쉬우므로 주의가 필요하다. 대부분의 경우, 앞의 방식을 대신해 constructor() 매서드에서 초기 state를 할당할 수 있다. 하지만 모달(Modal) 또는 툴팁과 같이 렌더링에 앞서 DOM 노드의 크기나 위치를 먼저 측정해야 하는 경우 이러한 방식이 필요할 수 있다.

 

주의

아래 메서드는 기존에 사용되었지만 이제는 사용하면 안 됩니다.

 

참고자료 :

 

React.Component – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

반응형

댓글