본문 바로가기

Programming

React JS Lifecycle Method 소개

관련 글

서론

React JS는 기본적으로 Component들은 React.createClass({})를 통해 생성되고, Mount하고 Unmount하는 과정과 this.state, this.props와 같은 data flow를 통해 Front를 핸들링한다.

이러한 Component에는 이 component가 어떠한 스펙을 갖고 있는지에 대한 component spec에 대해 정의를 해야하고, 또한 필요하다면 이 component가 Mount되기 전, Mount 된 후 혹은 Update 된 후 등 할일에 대해 정의할 수 있는 추가적인 life cycle method를 제공한다.

Component Specs

첫 번째로 Component Spec에 대해 설명을 하자면, 가장 중요한 spec으로 rendergetInitialState가 있다. 이 함수들은 지난 글에서도 사용했었다.

render

render 함수는 component를 생성하면 기본적으로 존재해야 하는 함수이고, 기본적으로 HTML DOM을 렌더링 해 사용자 들에게 보여주는 역할을 한다.

render 함수는 life cycle method 에서 다시한번 설명하겠지만, component가 Mount될 때, 그리고 this.setState에 의해 state 변화가 일어나서 DOM의 re-rendering이 필요할 때 호출된다.

getInitialState

getInitialState는 만약 해당 component가 this.state를 사용한다면 Mount되기 전 초기 state 값을 정할 때 사용된다.
일반적으로 아래와 같은 방식으로 사용된다.

var DomTest = React.createClass({
    getInitialState: function(){
        return {
            data: "",
            error: ""
        }
     }
});

이 외에 getDefaultProps, propTypes, mixins, static 그리고 dsiplayName 등이 있지만, 난 사용해 본적이 없기 때문에 설명만으로는 어떤 효과가 있고 어떤 때에 사용해야 하는지 잘 모르겠다. 문서를 확인하자.

Lifecycle Methods

Lifecycle Methods는 component의 특정 시점에 실행되는 함수들을 의미한다. 이 시점은 component가 Mount될 때일 수도 있고 Unmount될 때일수도 있다. 관련 내용은 문서에서 확인할 수 있다.

componentWillMount

  • 최초 render가 호출되기 직전 한 번 호출 된다.
  • 이 method에서 this.setState가 호출되어도 render는 한 번 호출 된다.

componentDidMount

  • 최초 render 호출 이후 한 번 호출되는 method이다.
  • 이 시점에서 React.findDOMNode(this)로 접근이 가능하다.

componentWillReceiveProps

  • 새로운 props를 받을 때 호출된다.
  • 최초 render 시에는 호출되지 않는다.
  • 이 method 내에서 this.setState()를 호출해도 추가적으로 render를 호출하지 않는다.


개인적으로, this.props로 받은 데이터는 수정하는 것을 권장하지 않는데, 해당 component에서 수정할 필요가 있을 때 this.state에 저장할 때 사용한다.


일반적으로 내가 사용하는 방법은 아래와 같다.(다른 분들도 이렇게 사용하는지는 나도 모르겠다)

var TestDOM = React.createClass({
    getInitialState: function(){
        return {propsData: this.props.data};
    },
    
    componentWillReceiveProps: function(nextProps){
        this.setState({data: nextProps.data});
    },
    
    render: function(){
        return (
            <DOM/>
        );
    }
});

shouldComponentUpdate

  • 새로운 propsstate를 받아 render를 호출하기 전에 호출된다.
  • 이 함수의 return 값이 true이면 render를 하고 false이면 render를 호출하지 않는다.
  • return이 false이면 componentWillUpdatecomponentDidMount도 실행되지 않는다.
  • 기본적으로 true를 return한다.


내가 일반적으로 사용하는 방식은 componentDidMount에서 setInterval 함수에서 ajax 요청을 보내고 각 요청마다 this.setState 함수를 호출하는데, 이 ajax 요청마다 render가 호출된다. 이 때 ajax로 가져온 값에 변화가 없다면 return false를 해 불필요한 render 호출을 막는다.

var TestDOM = React.createClass({
    getInitialState: function(){
        return {data: ""};
    },
    
    componentDidMount: function(){
        this.interval = setInterval(function(){
            $.ajax({
                url: "",
                success: function(resp){
                    this.setState({data: resp.data});
                }.bind(this)
            })
        }.bind(this), 1000);
    },
    
    shouldComponentUpdate: function(nextProps, nextState){
        // ajax로 가져온 data가 현재 data와 같으면 render를 호출하지 않음
        return this.state.data !== nextState.data;
    }
    
    componentWillUnMount: function(){
        clearInterval(this.interval);
    },
    
    render: function(){
        return <DOM/>
    }
})

componentWillUpdate

  • 새로운 propsstate를 받았을 때 render 직전 호출된다.
  • 최초 render 시에는 호출되지 않는다.
  • this.setState()를 호출할 수 없다.

componentDidUpdate

  • component의 업데이트가 DOM에 반영된 직후에 호출된다.
  • 최초 render 시에는 호출되지 않는다.

  • 내가 개발하다가 겪은 일인데, componentDidUpdate에서는 DOM에 변경을 일으키는 this.setState()를 조심스럽게 사용해야한다. 초기 DOM 변경으로 this.setState가 존재하는 componentDidUpdate를 호출하면 또 update가 일어나고 이 일이 계속 반복 된다.

조심스럽게 쓰자

componentWillUnmount

  • component가 DOM에서 Unmount되기 직전에 호출된다.

내가 사용했던 방법은 event를 bind하고 unbind할 때 사용하였다.

var TestDOM = React.createClass({
    componentDidMount: function(){
        $(window).bind("scroll", function(e){
            e.preventDefault();
            e.stopPropagation();
        })
    },
    
    componentWillUnmount: function(){
        $(window).unbind("scroll", function(e){
            e.preventDefault();
            e.stopPropagation();
        });
    },
    
    render: function(){
        return <DOM/>;
    }
});

또 겪은 일인데 unmount할 때 unbind를 했는데, unbind 에서는 preventDefaultstopPropagation 필요 없이 전체 다 해제 되는줄 알았지만 아니더라. 무조건 호출해야 정상적으로 돌아오더라.(React JS와는 관계없다)

Lifecycle 순서

  1. 상위 component에서 props로 데이터 받아 옴
  2. getInitialState - 초기 state 설정
  3. componentWillMount - 해당 component가 mount 되기 직전 실행
  4. componentDidMount - 해당 component가 mount 된 후 실행

아래 method들은 state 데이터에 변경이 있거나 혹은 상위 component에서 새로운 데이터를 전달 받을 때 실행된다.

  1. componentWillReceive - 새로운 props를 받을 때 실행

componentWillReceive를 이용해 새로운 props를 전달 받고, setState를 통해 state를 변경 할 경우 re-rendering이 발생하며 아래 method들을 실행한다.

  1. shouldComponentUpdate - return true이면 rendering을 하고, false이 면 무시한다
  2. componentWillUpdate - re-render 발생 후 사용자에게 보여지기 전 실행
  3. componentDidUpdate - re-render 발생 후 실행

그런데 하다보면 이상하게 getInitialState 호출 전에 props 데이터가 전달 안되는 경우가 있었다. 이유는 모르겠다.

아래 코드는 검색어를 이용해, 실시간으로 검색 결과를 리턴하는 코드이다. 아래 코드를 실행하고 개발자 도구의 console 창을 보면 lifecycle 순서를 확인할 수 있다.

console log