본문 바로가기
React

2021.07.19 React Life Cycle

by 해맑은 코린이 2021. 7. 21.

2021.07.19 React Life Cycle_정리노트

 

오늘도 역시 7장 정리!

 

오늘은 라이프사이클 ( 수명주기 ) 정리..! 렌더링 되는 시점을 제어하는거구.. 어렵지만 책따라서 차근차근 해볼 예정

 

 

모든 리액트 컴포넌트에는 라이프사이클이 존재.

컴포넌트의 수명은 페이지에 렌더링 되기 전인 준비 과정에서 시작하여 페이지에서 사라질 때 끝남.

그렇기에 프로젝트를 하다보면, 가끔 컴포넌트를 처음으로 렌더링할 때 어떤 작업을 처리하거나, 컴포넌트를 업데이트 하기 전 후로 어떤 작업을 처리해야할 수도 있다. 또, 불필요한 업데이트를 방지해야할 때가 오는데, 이 때 라이프사이클 메소드를 통해 처리한다. 

 

함수형은 새로 생긴 Hooks 에서 처리하기 때문에 오늘은 전반적인 흐름을 클래스형 컴포넌트를 이용해서 정리해볼 예정!

 

 

라이프 사이클 메서드는 총 9가지이며, 접두사에 의해서 뜻을 구분한다.

어떤 작업을 작동하기  메서드 Will

어떤 작업을 작동한 의 메서드 DId

 

또, 3가지의 카테고리로 나뉘는데 마운트, 업데이트, 언마운트 로 나뉜다.

 

마운트

DOM이 생성되고, 웹 브라우저상에 나타나는 것을 뜻함.

 

업데이트

컴포넌트는 총 네 가지의 경우에 업데이트 되는데, 

props 의 값이 바뀔 때

setState로 state 가 업데이트 될 때

부모 컴포넌트가 리렌더링 될 때 ( 자식 컴포넌트에 할당된 props 가 바뀌지 않아도, state 가 바뀌지 않아도 부모가 바뀌면 해당 )

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

 

 

언마운트

마운트의 반대 과정. 컴포넌트를 DOM 에서 제가하는 것을 뜻함.

 

 

이에 따른 과정과, 메소드들이 있지만 복잡하다 보니 나는 직접 치면서 정리할 예정! 

 

그 중에서 필수 메서드인 render() 메서드만 정리하고 나머지는 코드 치면서 정리!

 

render()

이 메서드는 컴포넌트 모양새(UI)를 정의. 컴포넌트에서 가장 중요한 메서드이자 라이프사이클 메서드 중 유일한 필수 메서드.

이 메서드 안에서 this.props 와 this.state 에 접근할 수 있으며, 리액트 요소 (div 와 같은 태그나 따로 선언한 컴포넌트 등등.. 아무것도 반환하고 싶지 않을 때는 null이나 false을 반환할 수 있도록 함. )를 반환한다. 

주의 사항은 이벤트 설정이 아닌 곳에서 setState를 사용하면 안되며, 브라우저의 DOM 에 접근해서도 안된다.

DOM 의 정보를 가져오거나 state 에 변화를 줄 때는, componentDidMount 메소드에서 처리할 수 있다.

 

 

 

 

 

src/LifeCycleSample.js ( 새로 생성 )

import React, { Component } from "react";

class LifeCycleSample extends Component {
  state = {
    number: 0,
    color: null,
  };

  myRef = null; //ref 설정할 부분

  constructor(props) {
    super(props);
    console.log("constructor");
  }

  // props 로 받아온 값을 state에 동기화 시키는 용도로 사용. 컴포넌트가 마운트 될 때와 업데이트 될 때 호출됨.

  static getDerivedStateFromProps(nextProps, prevState) {
    console.log('getDerivedStateFromProps');
    if (nextProps.color !== prevState.color) {
      return { color: nextProps.color };
    }
    return null;
  }
  // 컴포넌트를 만들고, 첫 렌더링을 다 마친 후 실행 된다.
  // 다른 자바스크립트 라이브러리 또는 프레임워크의 함수 호출, 이벤트 등록, setTimeout,setInterval ,네트워크 요청 등의 비동기 작업을 처리
  componentDidMount() {
    console.log("componentDidMount");
  }

  //  props 또는 state를 변경했을 때, 리렌더링을 시작할지 여부를 지정하는 메소드.
  // 반드시 true or false 반환해야하며, default 는 true.
  // 이 메서드 안에서 현재 props,state 는 this를 붙여 접근하고, 샐로 설정될 props,state 는 앞에 next 를 붙여 접근 가능.
  shouldComponentUpdate(nextProps, nextState) {
    console.log("shouldComponentUpdate", nextProps, nextState);
    return nextState.number % 10 !== 4; // 숫자 마지막 자리가 4면, 리렌더링 하지 마세여
  }
  // 컴포넌트를 DOM 에서 제거할 때 실행.componentDidMount에서 등록한 이벤트, 타이머, 직접 생성한 DOM 이 있다면, 여기서 제거함.
  componentWillUnmount() {
    console.log("componentWillUnmount");
  }

  handleClick = () => {
    this.setState({
      number: this.state.number + 1,
    });
  };
  // render 에서 만들어진 결과물이 브라우저에 실제로 반영되기 직전에 호출.
  // 이 메서드에서 반환하는 값은 componentDidUpdate 에서 세 번째 파라미터인 snapshot 값으로 전달받을 수 있다.
  // 주롤 스크롤바 위치와 같이 업데이트하기 직전의 값을 참고할 일이 있을 때 활용.
  getSnapshotBeforeUpdate(prevProps, proevState) {
    console.log("getSnapshotBeforeUpdate");
    if (prevProps.color !== this.props.color) {
      return this.myRef.style.color;
    }
    return null;
  }

  // 리렌더링 완료 후 실행. 
  // 업데이트 끝난 직후이기 때문에 DOM 관련 처리를 해도 무방. prevProps or prevState를 통해 컴포넌트가 이전에 가졌던 데이터에 접근 가능. 
  // getSnapshotBeforeUpdate 에서 반환한 값이 있으면, 여기서 snapshot 값을 전달받을 수 있음.
  componentDidUpdate(prevProps,prevState, snapshot){
    console.log('componentDidUpdate',prevProps,prevState)
    if(snapshot){
      console.log('업데이트 되기 전 색상' ,snapshot)
    }
  }

  render() {
    console.log('render')
    const style = {
      color:this.props.color
    }
    return (
    <div>
      <h1 style={style} ref={ref=>this.myRef=ref}>
        {this.state.number}
      </h1>
      <p>color:{this.state.color}</p>
      <button onClick={this.handleClick}>더하기</button>
    </div>);
  }
}

export default LifeCycleSample;

 

 

Wow.. 하나하나 주석을 달았는데 연결연결 되는 부분이 많군... 잘 다루려면 많이 쳐봐야할 것 같다.

쨋든 이 컴포넌트는 각 라이프 사이클 메서드를 실행할 때마다 콘솔 디버거에 기록하고, 부모 컴포넌트에서 props 로 색상을 받아 버튼을 누르면 state.number 값을 1씩 더한다.

 

getDerivedStateFromProps 에서는 부모에게서 받은 color 값을 state 에 동기화하고, getSnapshotBeforeUpdate 는 DOM 에서 변화가 일어나기 직전의 색상 속성을 snapshot 값을로 반환하여, componentDidUpdate 에서 조회할 수 있게 했다.

 

추가로 shouldComponenetUpdate 에서 state.number 값의 마지막 자리 수가 4이면, 리렌더링을 취소하도록 설정함!

 

으으... ㅠㅠ 복잡하다 복잡해 이제 App 으로 가서 props 랑 이것저것 설정해주러 갑씨다!

 

 

src/App

import React, { Component } from "react";
import LifeCycleSample from "./LifeCycleSample";

//  랜덤으로 hex 색상 코드 생성해주는 함수.
function getRandomColor() {
  return "#" + Math.floor(Math.random() * 16777215).toString(16);
}

class App extends Component {
  state = {
    color: "#000000",
  };

  handleClick = () => {
    this.setState({
      color: getRandomColor(),
    });
  };
  render() {
    return (
      <div>
        {/* 버튼 렌더링하고, 누를 때마다 handleCick 메서드 호출되도록 이벤트를 설정. */}
        <button onClick={this.handleClick}>랜덤색상</button>
        {/* color 를 props 로 설정 */}
        <LifeCycleSample color={this.state.color} />
      </div>
    );
  }
}

export default App;

 

getRandomColor 함수는 state 의 color 값을 랜덤 색상으로 설정. 16777215 를 hex로 변환하면, #ffffff ( 흰색 ) 이 되어 000000 ( 검정 ) 부터 ffffff ( 흰색 ) 까지 랜덤으로 반환. 

 

버튼을 렌더링하고 누를 때마다 handleClick 이 되도록 이벤트를 설정하고, 마지막으로 color props 를 설정해주면 끝!

 

 

자 이제 콘솔 실행화면 보기!

 

 

첫 렌더링이 끝나면, 생성자 메서드인 constructorrender, componnentDidMount 가 실행된다.

 

랜덤 색상 버튼을 누르면, 컴포넌트가 업데이트 되면서, shouldComponentUpdate 와  업데이트하기 직전의 값을 참고할 일이 있을 때 호출되는 getSnapshotBeforeUpdate 메서드가 호출된다. 

 

 

더하기 버튼을 누르면, props 값이 state로 동기화 되면서 , getDerivedStateFromProps 메소드가 호출되고, 끝자리가 4가 아닌 경우, shouldComponentUpdate 메소드가 호출된다. 끝자리가 4면, 업데이트를 취소한다.

 

 

 

 

 

중간중간 2번씩 렌더링 되는 이유는 React.StrictMode 가 적용되어 있기 때문! index.js 에서 제거하면 한번씩 작동한다! 개발 환경에서만 두 번 호출되니까 잘못렌더링 되는 것은 아님!

 

 

흐억... 겁나 복잡하균.. 나도 정리해놓고 다음에 또 봐야할 용도로 작성했음 ㅎㅅㅎ

 

 

이제 에러를 띄워서 처리 하는 과정 정리해봅시다!!!!

 

 

src/LifeCycleSample

 

render 함수에서는 에러는 주로 존재하지 않는 함수를 사용하려고 하거나 , 존재하지 않는 객체의 값을 조회하려고 할 때 발생한다. 의도적으로 존재하지 않는 props 인 missing 객체의 value 를 조회해서 렌더링 해줘보자.

 

 

 

에러가 잘 뜨는군. 근데 이건 개발 서버라서 그렇지 만약 사용자의 입장에서 에러가 뜬다면 저 x 표시를 누르면, 

 

 

이렇게 빈 화면만 뜰 거임. 이럴 때는 에러가 발생했어요 라고 따로 처리를 해주어야 하겠지!!

 

 

 

src/ErrorBoundary.js ( 새로 생성 )

import React, { Component } from "react";

class ErrorBoundary extends Component {
  state = {
    error: false,
  };

  componentDidCatch(error, info) {
    this.setState({
      error: true,
    });
    console.log({ error, info });
  }

  render() {
    if (this.state.error) return <div>에러가 발생했습니다!!!!!!!!</div>;
    return this.props.children;
  }
}

export default ErrorBoundary;

 

에러가 발생하면, componentDidCatch 메서드가 호출되어, this.state.error 값을 true 로 업데이트 한다. 그러고 childeren 값을 보여주게 했다. 그러면 App 으로 가자!!

 

 

src/App

 

 

이렇게 감싸주고 다시 실행화면!

 

 

이렇게 다급한 에러 메세지가 뜨면 성공!!!!


와이구야..... 정말 생각보다 복잡한 개념.... 나도 정리해놓고 자주 볼 생각으로 정리해서 한번에 역시 이해...는 다 못한 것 같다.

일단 메소드 이름이 직관적이긴 한데 여러개 쓰니까 너무 헷갈리는 듯 ㅎㅅㅎ ...!

 

그래도 오늘의 포스팅은 흐름 정리라 생각하고 다음에 또 수정할거 있으면 해야징.. 끝끄으ㅡㅡ끝!

'React' 카테고리의 다른 글

2021.07.24 React styling  (2) 2021.07.24
2021.07.23 React Hooks  (0) 2021.07.23
2021.07.19 React Component 반복  (1) 2021.07.19
2021.07.16 React ref  (0) 2021.07.16
07.13 React event handling  (0) 2021.07.14

댓글