본문 바로가기
  • soldonii's devlog
Javascript 공부/React

리액트의 생명 주기(LifeCycle) 메소드

by soldonii 2019. 12. 12.

*Udemy의 "Complete React Developer in 2020" 강의에서 학습한 내용을 정리한 포스팅입니다.

*자바스크립트와 리액트를 배우는 단계라 오류가 있을 수 있습니다. 틀린 내용은 댓글로 말씀해주시면 수정하겠습니다. 감사합니다. :)


리액트의 생명 주기(라이프사이클)

 

1. 생명 주기의 1단계 - 생성(Mounting)

생성 될 때

생성 단계는 컴포넌트가 constructor에 의해 초기화되고, rendering 과정을 거쳐 DOM에 최초로 그려지는 단계이다. 이 곳의 주요한 생명 주기 메소드는 componentDidMount가 있다. 생성 단계의 흐름을 순차적으로 정리해보자.

 

1. 컴포넌트의 base state가 최초로 constructor에 의해서 초기화 된다.

2. 초기화가 완료되면 render() 메소드가 실행된다. render()는 JSX로 작성된 코드를 자바스크립트가 이해할 수 있도록 변환한 후 HTML 형태로 DOM에 그려질 수 있도록 돕는 역할을 한다.

(위 두개의 단계가 끝나면 리액트는 화면에 표시해야 하는 컴포넌트가 어떻게 생겼는지, 어떠한 데이터를 가지고 있는지 알게 된다.)

3. 이제 실제로 DOM에 컴포넌트를 최초로 표시한다.(mounting)

4. mounting이 완료되면 componentDidMount 메소드가 실행된다.(즉 constructor -> render -> componentDidMount 순으로 실행)

 

모든 요소가 화면에 표시되면 이후 componentDidMount() 내부에서 API call 등을 통해 base state를 update시킬 수 있다. 최초에 데이터를 fetching하는 대신 모두 DOM에 그려진 후 맨 마지막에 fetching 하는 이유는 무엇일까? 

data를 fetching하는 과정은 시간이 얼마나 소요될 지 모른다. 그렇기 때문에 fetching하기 전에 그려야 하는 모든 형태를 DOM에 우선 그려놓고 이후 mount가 완료되면(didMount) 이후 componentDidMount() 안에서 API call 등을 진행하는 것이다.

 

2. 생명 주기의 2단계 - 업데이트(updating)

업데이트 할 때

 

컴포넌트에 전달된 props 혹은 state에 변화가 생길 경우에는 updating 단계로 넘어간다. 변화가 생기면 리액트는 해당 컴포넌트를 re-mounting하는 것이 아니라 re-rendering을 진행한다. 변화가 필요한 HTML 조각만을 찾아내 그 부분만 update하는 것이다.

 

1. mount된 컴포넌트에 props가 변경되거나, setState()로 state가 update되거나 forceUpdate()가 발생한다.

2. 변화된 데이터를 기반으로 기존의 컴포넌트를 re-rendering한다.

3. rendering이 완료되면 DOM에 변화된 부분을 update해서 표시한다.

4. componentDidUpdate() 메소드가 실행된다.

 

update 단계를 조금 더 분해해보면 못 보던 생명 주기 메소드가 나타난다. 아래 그림을 보자.

shouldComponentUpdate

 

# shouldComponentUpdate

위 그림을 보면 새로운 props, state를 받은 이후, render() 메소드가 실행되기 이전에 실행되는 생명 주기 메소드이다. shouldComponentUpdate는 update된 props 또는 state를 인자로 받은 후, 아래의 전체 프로세스, 즉 render()를 포함한 이후의 프로세스를 진행할지 말지를 결정하는 메소드이다. 이 메소드는 왜 필요할까?

 

예를 들어 App.js의 state 내부에 'message: ""' 라는 값이 존재하고, message state는 오직 App 컴포넌트 내부에만 존재하며, App 컴포넌트 내부에서 리턴시키는 다른 어떤 컴포넌트에도 props의 형태로 전달이 되지 않는 state라고 가정해보자. 만약 App 컴포넌트 내부에서 this.state.message의 값을 "" 공백에서 "something"으로 update시킬 경우, App 컴포넌트 전체가 re-rendering 될 것이다.

 

그런데 문제는, App 컴포넌트 내부에서 리턴되는 다른 컴포넌트들은 this.state.message를 props로 받지 않기 때문에 업데이트가 될 필요조차 없는 컴포넌트들이다. 그러나 App 컴포넌트 전체가 re-rendering 되면서 불필요하게 다른 컴포넌트들까지 업데이트가 되는 상황이다. 이는 성능저하를 일으키는 원인이 된다. 이 경우에 shouldComponentUpdate 메소드가 유용할 수 있다.

 

shouldComponentUpdate의 return 값을 false로 설정할 경우, 위 그림에서 render() 를 포함한 이후의 모든 프로세스는 실행되지 않는다. 즉 shouldComponentUpdate의 return 값이 false인 모든 컴포넌트들은 render()가 실행되지 않으며 따라서 DOM update, componentDidUpdate() 메소드 모두 실행되지 않는다.

shouldComponentUpdate(nextProps, nextState) {
  return nextProps.text !== this.props.text;
}

위 코드 처럼 update된 새로운 props(또는 state)가 기존의 this.props와 같지 않을 경우에는 true가 리턴되고, 따라서 값의 변동이 있을 때만 re-rendering을 실행하도록 한다.

 

이처럼 리액트의 생명 주기와 생명 주기 메소드를 이해하는 것은 좋은 리액트 개발자가 되기 위해 정말 중요하고 근본적인 것이다.

 

3. 생명 주기의 3단계 - 제거(unmounting)

제거할 때

마지막 3단계는 크게 복잡하지는 않다. 만약 DOM에 나타나있던 컴포넌트가 DOM에서 제거되어야 할 경우, componentWillUnmount() 메소드가 실행된다. DOM에서 사라진 컴포넌트가 다시 DOM에 그려질 경우에는 2단계가 아니라 1단계, 즉 Mount 단계(생성 단계)부터 다시 시작한다.

댓글