기록하는 개발자

<React 파헤치기-13> 컴포넌트 - 5. 컴포넌트 생명주기 본문

Web/React

<React 파헤치기-13> 컴포넌트 - 5. 컴포넌트 생명주기

밍맹030 2021. 12. 19. 17:16
728x90

컴포넌트의 생성부터 소멸까지의 과정을 컴포넌트의 생명주기(lifecycle) 이라고 한다.

이 생명주기마다 함수를 가지고 있으며, 함수를 이용해 특정 시점에 원하는 동작을 하게 만들 수 있다.

 

생명주기 함수는 총 8개로, react 엔진에서 자동으로 호출한다. 따라서 개발자가 임의대로 호출할 수 없다.

컴포넌트의 수명은 페이지에 렌더링 되기 전인 준비과정에서부터 페이지에서 사라질 때까지이다.

+) 라이프사이클 메서드는 클래스 컴포넌트에서만 사용할 수 있다(함수형컴포넌트에서는 주로 Hooks를 사용한다).

 

컴포넌트의 생명주기는 크게 컴포넌트의 생성, 생성 완료, 갱신 완료, 소멸 완료로 구분되어진다.

컴포넌트의 생성, 생성 완료 사이를 Mount, 생성 완료와 갱신 완료 사이를 Update, 갱신 완료와 소멸 완료 사이를 Unmount라고 부른다.

마운트(Mount)

DOM이 생성되고 웹 브라우저상에 나타나는 것

 

constructor(props)

이 함수는 맨 처음 생성될 때 한 번만 호출되며, 상태(state나 객체)를 선언할 때 사용된다.

constructor 함수를 정의할 때는 항상 super() 함수를 가장 위에 호출해야한다.

 - super() 함수는 property와 생명 주기 상태등을 초기화 하는 중요한 과정을 포함한다.

 

 

render( )

 

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

return값인 JSX를 반환하여 화면에 그려준다.

 

 

 

 

getDerivedStateFromProps(props, state)

 

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

상위 컴포넌트에서 전달 받은 property로 state 값을 연동할 때 주로 사용되며, 반환 값으로 state를 변경한다.

 

 

 

componentDidMount()

 

render() 함수가 JSX를 화면에 처음 그리고 나서(첫 렌더링을 다 마친 후) 실행되는 함수이다.

컴포넌트가 화면에 모두 표현 된 이후 해야하는 작업들을 이 함수를 통해 수행할 수 있다.

 

 

 

Update

update는 아래 네 가지의 상황에서 발생한다.

props의 변경
state의 변경
부모 컴포넌트의 re-rendering
foceUpdate() 함수의 사용

 

 

shouldComponentUpdate(nextProps, nextState)

 

property를 변경하거나 setState 함수 호출을 통해 state를 변경했을 때 화면에 새로 출력할지 말지를 판단한다.

이 함수는 true 또는 false 를 반환하며, 해당 반환값을 통해 re-rendering 여부를 지정한다.

데이터 변화를 비교하는 작업을 포함하기 때문에 react 성능에 영향을 많이 준다.

 

- 컴포넌트를 만들 때 따로 수정하지 않는 경우에는 default로 지정된 true를 반환하고,

  render-getSnapshotBeforeUpdate-componentDidUpdate 를 차례로 호출한다.

- false 값을 반환하면, 업데이트 과정(re-rendering)을 중지한다.

 

 주로 프로젝트 성능을 최적화 할 때 또는 리렌더링을 방지 할 때 false 값을 반환하도록한다.

setState가 아닌 강제로 화면에 출력을 해주는 forceUpdate를 호출하면 이 함수는 호출되지 않는다.

 

 

getSnapshotBeforeUpdate(prevProps, prevState)

 

컴포넌트가 화면에 실제로 출력되기 전에 호출된다.

보통 화면에 출력된 요소의 크기, 스크롤 위치 등의 DOM 정보에 접근할 때 사용된다.

 

 

 

componentDidUpdate(prevProps, prevState, snapshot)

 

컴포넌트가 실제 화면에 출력된 이후 호출된다.

 

- 부모 컴포넌트로부터 이전 property와 이전 state값을 전달 받는다.

- getSnapshotBeforeUpdate 로부터 반환된 값인 snapshot을 인자로 받아 해당 정보를 통해 스크롤 위치를 옮기거나 커서를 이동 시키는 등 DOM 정보를 변결할 수 있따.

 

 

Unmount

컴포넌트를 DOM에서 제거하는 것(Mount 의 반대 과정)

 

componentWillUnmount()

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

componentDidMount 에서 등록한 이벤트, 타이머, 직접 생성한 DOM이 있다면, 여기서 해제 작업을 해야한다.

이러한 해제 작업이 생략될 경우 메모리 누수 현상의 발생으로 웹 브라우저의 작동이 멈출 수도 있다.

 

메모리 누수 : https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EB%A6%AC_%EB%88%84%EC%88%98

 

메모리 누수 - 위키백과, 우리 모두의 백과사전

 

ko.wikipedia.org

 

 

두 가지의 counter를 통해 getDerivedStateFromProps 함수의 동작 원리를 알아보자

import React from 'react';

class Counter extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            count : props.count
        };
        this.addCount = this.addCount.bind(this);
    }

    addCount(){
        this.setState(({count}) => ({
            count : count + 1
        }));
    }
    render(){
        return(
            <div>
                count : {this.state.count}
                <button onClick={this.addCount}> + </button>
            </div>
        );
    }    
}
export default Counter

 

import React from 'react';

class NewCounter extends React.Component {
    constructor(props){
        super(props);
        this.state = {};
        this.addCount = this.addCount.bind(this);
    }
    
    static getDerivedStateFromProps(props, state){
        const {count} = props;
        return{
            count,
            newCount : count === state.count ? state.newCount : count,
        };
    }
    addCount(){
        this.setState(({newCount}) => ({
            newCount : newCount + 1
        }));
    }
    render(){
        return(
            <div>
                count : {this.state.newCount}
                <button onClick={this.addCount}> + </button>
            </div>
        );
    }    
}
export default NewCounter

 

import React from 'react';
import Counter from './Counter';
import NewCounter from './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> <NewCounter count={this.state.count}/> </div>
                <button onClick={this.resetCount}> {this.state.count+10}으로 초기화 </button>
            </div>
        );
    }    
}
export default App;

실행 초기 화면

실행 후 두 counter의 더하기 버튼을 두 번씩 누른 화면

App 컴포넌트의 초기화 버튼 클릭

 

위와 같이 초기화 버튼을 클릭했을 때는 NewCounter의 state만 변한다.

NewCounter는 getDerivedStateFromProps 함수의 매개변수인 props를 통해 부모의 count 변화를 감지하고 state를 통해서는 자신의 state 변화를 감지한다. 따라서 부모의 state의 count가 +10이 되자마자 getDerivedStateFromProps 가 호출되어 삼항연산자를 통해 최신의 값으로 state를 업데이트 해준다.

 

반면 Counter는 props 즉, 상위 컴포넌트의 property가 바뀌어도 값을 전달 받지 않기 때문에 App의 state가 변경되어도 Counter의 state에는 영향을 주지 않는다.

728x90