React.js - 컴포넌트 생명주기(Life Cycle)

Gyu·2022년 4월 5일
7

React.js

목록 보기
6/20
post-thumbnail

리액트 컴포넌트 생명주기(Life Cycle)

  • 리액트의 컴포넌트는 생명주기를 가진다. 생명주기란 컴포넌트가 생성되고 사용되고 소멸될 때 까지 일련의 과정을 말한다. 생명주기 안에서는 특정 시점에 자동으로 호출되는 메서드가 있는데, 이를 라이프 사이클 이벤트라고 한다.
  • 모든 React 컴포넌트는 라이프 사이클 이벤트가 있다. 라이프사이클 이벤트는 컴포넌트가 수행한 작업이나 앞으로 수행할 작업에 따라 특정 시점에 실행된다. 어떤 이벤트는 한 번만 실행되기도 하고, 어떤 이벤트는 계속해서 실행된다.
  • React는 라이프 사이클 이벤트를 기반으로 컴포넌트의 동작을 제어하고, 컴포넌트의 작업 수행을 향상시키는 사용자 정의 로직을 구현할 수 있다. 예를 들면 라이프 사이클 이벤트 중에는 재렌더링 여부를 정할 수 있는 이벤트가 있는데, 이 이벤트를 이용하면 불필요하게 렌더링되는 것을 방지하여 성능을 개선할 수 있다. 또한 라이프 사이클 이벤트를 이용하여 원하는 시점에 서버에서 데이터를 가져오거나, DOM 이벤트 또는 다른 프론트엔드 라이브러리와 통합할 때 사용할 수 있다.
  • 라이프 사이클 이벤트를 컴퓨터 프로그래밍에서 말하는 후킹과 비슷하다.

💡 후킹(Hooking이란?)

운영 체제나 응용 소프트웨어 등의 각종 컴퓨터 프로그램에서 소프트웨어 구성 요소 간에 발생하는 함수 호출, 메시지, 이벤트 등을 중간에서 바꾸거나 가로채는 명령, 방법, 기술이나 행위를 말한다. 이때 이러한 간섭된 함수 호출, 이벤트 또는 메시지를 처리하는 코드를 훅(영어: hook)라고 한다.

라이프 사이클 이벤트 분류

  • React는 여러가지 컴포넌트 이벤트를 세 가지 유형으로 정의한다. 각 분류에 따라 이벤트가 발생되는 횟수가 다르다.

마운팅(mounting) 이벤트

  • React 엘리먼트(컴포넌트 클래스의 인스턴스)를 DOM 노드에 추가할 때 발생하며, 한 번만 실행된다.
  • 컴포넌트가 시작되면 우선 context, defaultProps와 state를 저장한다. 그 후에 componentWillMount() 메소드를 호출한다. 그리고 render로 컴포넌트를 DOM에 부착한 후 Mount가 완료된 후 componentDidMount() 가 호출된다.
    • componentWillMount() : DOM에 삽입하기 전에 실행된다. 마우팅 중이기 때문에 props나 state에 접근 할 수 있으나 마운팅 중이기 때문에 이 값을 변경하면 안된다. 또한 아직 render() 함수가 실행 전이기 때문에 DOM에 접근 할 수 없다.
    • componentDidMount() : DOM에 삽입되어 렌더링이 완료된 후 실행된다. DOM에 접근할 수 있다. 주로 이 단게에서 AJAX 요청을 하거나, setTimeout, setInterval같은 행동을 한다.
  • 실행 순서
    1. state, context, defaultProps 저장
    2. componentWillMount()
    3. render()
    4. componentDidMount()

갱신(updating) 이벤트

  • 속성이나 상태가 변경되어 React 엘리먼트를 업데이트할 때 발생하며, 여러 번 실행된다.
  • 이벤트 종류
    • componentWillReceiveProps(nextProps) : 컴포넌트가 props를 받기 직전에 실행된다. 바뀔 props에 대한 정보를 매개변수로 갖는다. state update 과정에서는 호출 되지 않는다.
    • shouldComponentUpdate(nextProps, nextState) : 컴포넌트 업데이트 직전에서 호출되는 메소드드로, return false를 하면 render을 취소할 수 있다. 컴포넌트가 갱신되는 조건을 정의해서 재렌더링을 최적화할 수 있다.(불필요한 update 제한 가능) 불 값을 반환한다. 첫 번째 매개변수로 바뀔 props에 대한 정보를, 두 번째 매개변수로 바뀔 state 정보를 갖는다.
    • componentWillUpdate(nextProps, nextState) : 컴포넌트가 갱신되기 직전에 실행된다. 첫 번째 매개변수로 바뀔 props에 대한 정보를, 두 번째 매개변수로 바뀔 state 정보를 갖는다. 이 단계에서는 state를 변경해서는 안된다. 아직 props가 업데이트 되지 않았으므로, state를 변경하면 또 shouldComponentUpdate() 이벤트가 발생하기 때문이다.(무한루프 발생)
    • componentDidUpdate(prevProps, prevState) : 컴포넌트가 갱신된 후에 실행된다. 이 이벤트는 이미 업데이트되었기 때문에 첫 번째 매개변수로 이전 props에 대한 정보를, 두 번째 매개변수로 이전 state 정보를 갖는다. 이 단계에서는 render가 완료되었기 때문에 DOM에 접근할 수 있다.
  • props가 update 되었을 때 과정
    1. componentWillReceiveProps()
    2. shouldComponentUpdate()
    3. componentWillUpdate()
    4. render()
    5. componentDidUpdate()
  • state가 update 되었을 때 과정
    1. shouldComponentUpdate()
    2. componentWillUpdate()
    3. render()
    4. componentDidUpdate()

언마운팅(unmounting) 이벤트

  • React 엘리먼트를 DOM에서 제거할 때 발생하며, 한 번만 실행된다.
  • componentWillUnmount() : 컴포넌트를 DOM에서 제거하기 전에 실행되며, 주로 연결했던 이벤트 리스너를 제거하는 등의 여러 가지 정리 활동을 한다.

Error

  • 리액트 16에서 추가된 이벤트로, 에러 발생 시 한 번만 실행한다.
    componentDidCatch(error, info) {
      console.error(error, info);
    }
  • 위와 같이 사용하고, 최상위 컴포넌트에 한 번만 작성하면 된다. 에러 발생 시 어떻게 대처할 것인지를 정의할 수 있다.

getDerivedStateFromProps

  • 리액트 16에서 추가된 이벤트로 props가 바뀌면 그에 따라 state도 같이 바꿔주는 이벤트

각 라이프 사이클에 대한 자세한 설명은 이곳 참고

라이프 사이클 이벤트 실행 순서

  • constructor()를 포함한 라이프 사이클 실행 순서는 아래와 같다.
    1. constructor() : 엘리먼트를 생성하여 기본 state와 prop을 설정할 때 실행된다.
    2. componentWillMount() : 컴포넌트를 DOM에 삽입하기 전 실행
    3. render()
    4. componentDidMount() : DOM에 삽입되어 렌더링이 완료된 후 실행
    5. componentWillReceiveProps(nextProps) : 컴포넌트가 props를 받기 직전 실행
    6. shouldComponentUpdate(nextProps, nextState) : 컴포넌트가 갱신되기 전 실행. 랜더링 유무 설정 가능
    7. componentWillUpdate(nextProps, nextState) : 컴포넌트가 갱신되기 직전 실행
    8. render()
    9. componentDidUpdate(prevProps, prevState) : 컴포넌트가 갱신된 후에 실행
    10. componentWillUnmount() : 컴포넌트를 DOM에서 제거하기 전 실행
  • React는 엘리먼트를 먼저 렌더링(= render()함수 호출)하고 나서 DOM에 추가한다.

💡 리액트 17부터는 componentWillMount(), componentWillUpdate(), componentWillReceiveProps() 라이프 사이클이 deprecated 된다.

라이프 사이클 이벤트 예제

class Logger extends React.Component {
    constructor(props) {
        super(props)
        console.log(‘constructor’)
    }

    componentWillMount() {
        console.log(‘componentWillMount 실행’)
    }

    componentDidMount(e) {
        console.log(‘componentDidMount 실행’)
        console.log(DOM node:, ReactDOM.findDOMNode(this))
    }

    componentWillReceiveProps(newProps) {
        console.log(‘componentWillReceiveProps 실행’)
        console.log(‘새로운 속성:, newProps)
    }

    shouldComponentUpdate(newProps, newState) {
        console.log(‘shouldComponentUpdate 실행’)
        console.log(‘새로운 속성:, newProps)
        console.log(‘새로운 상태:, newState)
        return true
    }

    componentWillUpdate(newProps, newState) {
        console.log(‘componentWillUpdate 실행’)
        console.log(‘새로운 속성:, newProps)
        console.log(‘새로운 상태:, newState)
    }

    componentDidUpdate(oldProps, oldState) {
        console.log(‘componentDidUpdate 실행’)
        console.log(‘이전 속성:, oldProps)
        console.log(‘이전 상태:, oldState)
    }

    componentWillUnmount() {
        console.log(‘componentWillUnmount’)
    }

    render() {
        return (
            <div>{this.props.time}</div>
        )
    }
}
profile
애기 프론트 엔드 개발자

0개의 댓글