출처: https://bumcrush.tistory.com/182 [맑음때때로 여름]

구글링 해보니까 이게 제일 비슷한 것 같아서 이걸로 퍼옴

 

생성과정(start) / 갱신과정(props changed & state changed) / 소멸과정 (componentWillUnmount)

shouldComponentUpdate 함수의 반환값(true/false)에 따라 갱신과정은 생략되기도 한다. (갱신과정생략)

 

 

 

생성 과정의 생명주기 함수들 실행해보기

 

1. constructor(props)함수

맨 처음에 생성될 때 한번만 호출되며 상태(state)를 선언할 떄 사용된다.

항상 super()함수를 가장 위에 호출해야 한다.

=> super() 함수에는 프로퍼티와 생명 주기 상태등을 초기화하는 과정을 포함하고 있기 때문.

 

2. render()함수

데이터가 변경되어 새 화면을 그려야 할 때 자동으로 호출되는 함수

render()가 반환하는 JSX를 화면에 그려준다.

 

3. static getDerivedStateFromProps(props, state)함수 (이름왜케길어)

정적 함수로, 함수안에서 this.props나 this.state와 같은 방법으로 값에 접근이 불가하다.

만약 값에 접근하려면 인자로 전달된 props, state를 이용해야 하는데,

이때 props는 상위 컴포넌트에서 전달된 값이며, state는 현재 컴포넌트의 state값이다.

> 이 함수는 상위 컴포넌트에서 전달받은 프로퍼티로 state값을 연동할 때 주로 사용하며,

   반환 값으로 state를 변경한다.

 

4. componentDidMount()함수

render함수가 JSX를 화면에 그린 이후 호출되는 함수

=> 컴포넌트가 화면에 모두 표횬된 이후에 해야 하는 작업들은 여기서하면 된다.

 

 

 

 

[그림에서는 START부분]

import React from "react";

class LifecycleExample extends React.Component {
  static getDerivedStateFromProps() {
    console.log("getDerivedStateFromProps 호출");
    return {};
  }

  constructor(props) {
    super(props);
    //getDerivedStateFromProps()함수를 사용하므로
    //경고메세지를 건너뛰기 위해 state 초기값 설정

    this.state = {};
    console.log("constructor 호출");
  }

  componentDidMount() {
    console.log("ComponentDidMount 호출");
  }

  componentDidUpdate() {
    console.log("ComponentDidUpdate 호출");
  }

  componentWillUnmount() {
    console.log("ComponentWillUnmount 호출");
    return {};
  }

  getSnapshotBeforeUpdate() {
    console.log("getSnapshotBeforeUpdate 호출");
    return {};
  }

  shouldComponentUpdate() {
    console.log("shouldComponentUpdate 호출");
    return true;
  }

  render() {
    console.log("render 호출");
    return null;
  }
}

export default LifecycleExample;

 

 

변경 과정의 생명주기 함수들 실행해보기

상위 컴포넌트의 프로퍼티나 state의 변화가 생기면 실행된다.

 

1. shouldComponentUpdate(nextProps, nextState)

프로퍼티를 변경하거나, setState()함수를 호출하여 state값을 변경하면 '화면을 새로 출력해야하는지' 판단하는 함수

** 이 함수는 화면을 새로 출력할지 말지 판단하며, 데이터 변화를 비교하는 작업을 포함하므로 리액트 성능에 영향을 많이 준다.

forceUpdate()함수를 호출하여 강제로 화면을 출력하면 이함수는 호출되지 않는다.

 

2. getSnapshotBeforeUpdate(prevProps, prevState)

컴포넌트의 변경된 내용이 가상화면에 완성된 이후에 호출되는 함수

컴포넌트가 화면에 실제로 출력되기 전에 호출되므로 화면에 출력될 엘리먼트의 크기, 또는 스크롤 위치등의 DOM정보에 접근할 때 사용된다.

 

3. componentDidUpdate(prevProps, PrevState, snapshot)함수

실제 화면에 출력된 이후 호출되는 함수

부모 컴포넌트로부터 전달된 이전 프로퍼티(prevProps)와 이전 state값(prevState)과 함께, getSnapshotBeforeUpdate() 함수에서 반환된 값(snapshot)을 인자로 전달 받는다.

이 값들을 이용하여 스크롤의 위치를 옮기거나 커서를 옮기는 등의 DOM정보를 변경할 때 사용된다.

 

 

  componentDidMount() {
    console.log("ComponentDidMount 호출");
    // state값을 변경
    this.setState({updated : true});
  }

 

shouldComponentUpdate() 반환값을 false로 하면

-> 리액트 엔진은 데이터 비교 후 변경 사항이 없다고 판단하므로, 변경과정의 생명주기 함수가 실행되지 않는다.

  shouldComponentUpdate() {
    console.log("shouldComponentUpdate 호출");
    // false로 변경
    return false;
  }

결과값과 상관없이 화면 동기화를 진행하고 싶다면 forceUpdate()함수를 사용해야 한다.

  componentDidMount() {
    console.log("ComponentDidMount 호출");
    this.forceUpdate();
  }

 

소멸 과정의 생명주기 함수들 실행해보기

컴포넌트가 화면에서 생략되면 시작

 

componentWillUnmount()

컴포넌트가 소멸되기 직전에 호출되는 함수

보통 컴포넌트에서 감시하고 있는 작업들을 해제할 때 필요한 함수이다 (뭔말이지?)

예를 들어 컴포넌트에 setInterval()함수가 사용되었다면 이 함수에서 setInterval()함수를 clearInterval()함수로 해제해야 한다. (그렇군..)

이러한 해제 작업이 생략되면 메모리 누수현상이 발생하여 브라우저가 멈추기도 하기 때문이다.

 

 

 

App 컴포넌트에서 LifecycleExample 컴포넌트를 그리지 않도록(null) 코드를 작성

/// app.jsx


import React from "react";
import LifecycleExample from "./03/LifecycleExample";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hadDestroyed: false };
  }
  componentDidMount() {
    this.setState({ hadDestroyed: true });
  }

  render() {
    return (
      <div>
        <div>{this.state.hadDestroyed ? null : <LifecycleExample />}</div>
      </div>
    );
  }
}

export default App;

 

 

카운터 프로그램을 만들며 생명주기 함수 사용해보기

 

 

counter.jsx

: state의 초기값을 설정할 때 props.count와 같이 프로퍼티로 받은 값을 사용한다.

import React, { Component } from "react";

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // count 초기값을 프로퍼티에서 전달된 값으로 설정한다.
      count: props.count,
    };
    this.increaseCount = this.increaseCount.bind(this);
  }
  increaseCount() {
    this.setState(({ count }) => ({
      count: count + 1,
    }));
  }
  render() {
    return (
      <div>
        현재카운트 : {this.state.count}
        <button onClick={this.increaseCount}>카운트증가</button>
      </div>
    );
  }
}

export default Counter;

NewCount.jsx

gerDerfivedStateFromProps() 함수를 사용하여 변경된 프로퍼티 값으로 state값을 갱신한다.

app컴포넌트가 전달한 최초의 프로퍼티 값은 state.count에 저장되며,

NewCounter 컴포넌트는 state.newCount로 증가값을 따로 분리하여 관리

=> state.count가 아니라 state.newCount로 증가값을  관리하는 이유는,

getDerivedStateFromProps()함수는 다른 프로퍼티가 변경되어도 호출되기 때문이다.

import React, { Component } from "react";

class NewCounter extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.increaseCount = this.increaseCount.bind(this);
  }

  static getDerivedStateFromProps(props, state) {
    const { count } = props;
    return {
      //프로퍼티에서 전달된 count값을 보관한다
      count,
      newCount:
        count === state.count
          ? //프로퍼티가 변경되지 않았다면 기존state값으로 설정
            state.newCount
          : //변경되었다면 변경된 값으로 설정
            count,
    };
  }

  increaseCount() {
    this.setState(({ newCount }) => ({
      newCount: newCount + 1,
    }));
  }
  render() {
    return (
      <div>
        현재카운트 : {this.state.newCount}
        <button onClick={this.increaseCount}>카운트증가</button>
      </div>
    );
  }
}

export default NewCounter;

 

 

import React from "react";
import Counter from "./03/Counter";
import NewCount from "./03/NewCounter";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 10 };
    this.resetCount = this.resetCount.bind(this);
  }

  resetCount() {
    this.setState(({ count }) => ({ count: count + 10 }));
  }

  render() {
    return (
      <div>
        <div>
          <Counter count={this.state.count} />
        </div>
        <div>
          <NewCount count={this.state.count} />
        </div>
        <button onClick={this.resetCount}>
          {this.state.count + 10}으로 초기화
        </button>
      </div>
    );
  }
}

export default App;

 

 

NewCounter 컴포넌트만 gerDerivedStateFromProps()함수로 App 컴포넌트부터 갱신된 프로퍼티 값을 동기화 했기 때문에 초기화버튼은 NewCounter에만 적용된다.

Counter 컴포넌트는 처음 생성될때만 프로퍼티 값을 설정하므로 갱신 과정에서는 변경X

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+ Recent posts