Pandaman Blog

[React.js] Component lifecycle 본문

Front end/React

[React.js] Component lifecycle

oyg0420 2020. 3. 17. 22:56

 

컴포넌트 생애주기는 컴포넌트가 마운트 되거나 갱신될 때 호출되는 일련의 메서드로 이루어진다.

컴포넌트 생애주기 메서드는 렌더링 전, 후로 호출된다. 컴포넌트 생애주기 메서드를 알아야 하는 이유는 우리가 React를 효과적으로 사용하기 위해서다.
왜 효과적으로 사용할 수 있는지는 설명과 예제를 통해서 이해할 수 있다.

컴포넌트 생애주기는 크게 마운트 생애주기와 갱신 생애주기로 나눌 수 있다.

마운트 생애주기 API

아래는 마운트 생애주기에 따라 호출되는 API 알아보기 위한 예제이다.

import React from "react";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    console.log("call constructor");
  }

  componentWillMount() {
    console.log("call componentWillMount");
  }

  componentDidMount() {
    console.log("call componentDidMount");
  }

  render() {
    console.log("call render");
    return <div></div>;
  }
}

위 코드를 실행하면 "call constructor" -> "call componentWillMount" -> "call render" -> "call componentDidMount" 순으로 로그가 남는 것을 확인할 수 있다. 아래에서 각각의 메서드에 대해 간단하게 알아보자.

contructor

contructor는 생애주기의 메서드가 아니다. 컴포넌트의 초기화에 contructor를 사용되며, 컴포넌트가 마운트 되기 전에 최초로 호출되는 함수이기 때문에 넣어봤다.

componentWillMount

상태가 초기화되었다면 componentWillMount()가 호출된다. componentWillMount는 주로 초기화된 state의 랜더링 전에 변경할 때나, fetch 할 때 사용된다.
현재는 레거시 생명주기 메서드로 분류되어 사용하지 않는 것을 추천한다.
componentWillMount에서 setState로 상태를 변경하고자 했다면, contructor에서 state가 초기화될 때 상태 값을 미리 할당하여 사용하고, fetch를 하는 경우는 아래에서 설명할 componentDidMount에서 사용하는 것을 React 공식 홈페이지에 권고하고 있다.

render

컴포넌트 렌더링을 담당한다.

componentDidMount

컴포넌트 렌더링 직후 componentDidMount API가 호출된다.
componentDidMount는 어떤 경우 사용하는 것이 좋을까?

  1. 페이지에 진입할 때 필요한 데이터를 요청 경우: 주로 fetch를 하는 경우에 사용된다.
  2. DOM node를 조작하는 경우: componentDidMount는 render함수 이후에 작동하므로 DOM 조작이 가능하다.
  3. timer 이벤트를 발생시키는 경우

아래는 componentDidMount 메서드에서 timer 이벤트를 발생시킨 예제이다.

  componentDidMount() {
    setInterval(() => this.getCount(), 1000);
  }

  getCount = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1
    });
  }

렌더링 직후 componentDidMount가 호출되면서 그 내부의 함수 setInterval가 작동한다.
콜백 함수 getCount는 대기열에 대기하다가 실행 스택에 푸시되어 실행되면 count가 1씩 증가된고 다시 render()를 호출한다.

갱신 생애주기 API

갱신 생애주기는 컴포넌트의 상태가 변경되었거나, 부모 컴포넌트로부터 새로운 property를 받는 경우 호출되는 메서드이다.

componentWillReceiveProps(nextProps)

부모 컴포넌트로부터 전달된 새 property가 전달될 때 호출된다. 리액트 공식 홈페이지에서는 이 생명주기 메서드를 사용하면 버그를 만들거나, 일관성을 해칠 수 있습니다.라고 하며 사용하지 않는 것을 권장한다. 하지만 분명 레거시로 남아 있는 이 녀석을 마주칠 수 있기 때문에 어떻게 사용하는지 살펴보자.

아래의 예제를 살펴보자.

componentWillReceiveProps(nextProps) {
  const { id } = this.props;
  if (id !== nextProps.id) {
    this.fetchPerson();
  }
}

부모 컴포넌트로부터 전달받은 property id가 변경되었다면, componentWillReceiveProps 메서드가 호출된다. 기존의 id와 새로운 id의 값을 비교하여 변경된 경우 원하는 행동을 할 수 있다. 필자는 property의 값이 변경이 되었을 때 로컬 State를 변경할 때나, fectch api를 호출할 때 사용한다.

shouldComponentUpdate(nextProps, nextState)

shouldComponentUpdate는 state 또는 props가 갱신될 때 render() 직전에 호출되는 메서드이다.
shouldComponentUpdate의 기본적으로 true를 리턴한다. 그 의미는 true를 반환한 경우 state, props를 갱신한다. 반환 값이 false인 경우는 state, props를 갱신하지 않는다. 따라서, 성능을 최적화하기에 유용하다.

아래 예제를 살펴보자.

import React from "react";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };
    console.log("call constructor");
  }

  shouldComponentUpdate(nextProps, nextState) {
    const { name } = this.state;
    return name !== nextState.name;
  }

  onClickHandler = () => {
    this.setState({
      name: ""
    });
  };

  render() {
    const { name } = this.state;
    console.log("call render");
    return (
      <div>
        <button type="button" onClick={this.onClickHandler}>
          Click me
        </button> 
        result: {name}
      </div>
    );
  }
}

위 코드에서 button를 클릭하면 핸들러 함수가 호출되고 setState 비동기 함수를 통해 상태 name을 기존 값과 동일한 빈 문자열을 할당한다.
render() 호출 직전 shouldComponentUpdate가 호출되는데, name !== nextState.name가 false 이기 때문에 state의 갱신을 일어나지 않는다.
shouldComponentUpdate의 반환 값을 false로 고정시킨다면 state, props의 갱신을 일어나지 않기 때문에 필요에 따라 잘 사용한다면 불 필요한 갱신을 막아 성능을 최적화하는데 큰 도움을 줄 것이다.

componentDidUpdate(prevProps, prevState, snapshot)

componentDidUpdate는 갱신이 일어난 직후에 호출된다. 주로, state 또는 props가 갱신되고 fetch api를 호출하는 경우에 사용된다.
예제를 살펴보자.

  componentDidUpdate(prevProps, prevState) {
    const { name } = this.state;
    if (prevState.name !=== name) {
      this.fetchPandamanInfo();
    }
  }

이전의 상태 name과 현재 상태 name을 비교하여 변경이 되었다면 fetchPandamanInfo를 호출하는 코드이다.
여기서 중요한 점은 조건문 if(prevState.name !=== name)으로 감싸지 않는다면 props 또는 state가 변경될 때마다 호출되어 성능 저하가 될 수 있다. 따라서 조건문을 통해 원하는 데이터가 변경되었을 때에 원하는 액션을 취하도록 하자.

 

다음 시간에는 리덕스에 대해 알아보도록 하겠습니다.


파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음

Comments