React Component Lifecycle (컴포넌트 생명 주기)
컴포넌트는 생명주기마다 함수를 가지고 있는데 이 함수들을 이용하면 특정 시점에 원하는 동작을 하도록 만들 수도 있다.
아래는 App컴포넌트의 자식 컴포넌트인 LifeCycleExample 컴포넌트를 만들어 생명주기 함수의 흐름을 살펴 보았다.
//단축키 RCFC하면 생명주기 함수와 함께 생성된다고.....
import React, { Component } from 'react';
class LifeCycleExample extends Component {
/** getDerivedStateFromProps(props,state)
* 1. 정적 함수이다.
* 2. 인자로 props,state 전달할 수 있다.
* 3. 인자로 전달된 props로 상위 컴포넌트에 전달된 값을 가져올 수 있다.
* 4. 인자로 전달된 state는 현재 컴포넌트의 state 값이다.
* 5. 상위 컴포넌트에서 전달받은 프로퍼티로 state값을 연동할 때 주로 사용된다.
* 6. 반환 값으로 state를 변경한다.
*/
static getDerivedStateFromProps() {
console.log('getDerivedStateFromProps 호출!');
return {};
}
/** constructor(props)
* 1. 맨 처음 생성 될 때 한 번만 호출됨.
* 2. 상태(state 또는 객체 변수)를 선언할 때 사용된다.
* 3. super() 함수를 가장 위에 호출해야 한다. 꼭! (프로퍼티와 생명주기 상태등을 초기화하는 중요과정포함...!)
*/
constructor(props) {
super(props);
console.log('constructor 호출!');
//이 후에 추가적인 데이터 state데이터 혹은 변수를 선언한다.
this.state = {}; //getDerivedStateFromProps() 함수를 사용하므로 경고 메시지 건너 뛰기위해 초깃값 설정.
}
/** componentDidMount()
* 1. render()함수가 jsx를 화면에 그린 이후에 호출되는 함수이다.
* 2. 모든 컴포넌트가 화면에 표현된 이후에 해야 할 작업들은 이 함수에서 하면 된다.
*/
componentDidMount() {
console.log('componentDidMount 호출!');
}
/** componentDidUpdate(prevProps,prevState,snapshot)
* 1. 컴포넌트가 실제 화면에 출력된 이후에 호출되는 함수.
* 2. 인자 prevProps는 부모 컴포넌트로부터 전달된 이전 프로퍼티이다.
* 2. 인자 prevState는 부모 컴포넌트로부터 전달된 이전 state값이다.
* 3. 인자 snapshot은 getSnapshotBeforeUpdate() 함수에서 반환된 값을 전달 받는다.
* 4. 해당 함수에서는 위 인자들의 값을 이용해서 스크롤 위치를 옮기거나 커서를 이동시키는 등의 DOM정보를 변경할 때 사용한다.
*/
componentDidUpdate() {
console.log('componentDidUpdate 호출!');
}
/** componentWillUnmount()
* 1. 컴포넌트가 소멸되지 직전에 호출되는 함수
* 2. 컴포넌트에서 감시하고 있는 작업들을 해제할 때 필요한 함수
* 3. 예를 들어 컴포넌트에 setInterval() 함수가 사용되었다면 이 함수에 setInterval()함수를 clearInterval() 함수로 해제해야 한다.
* 4. 3.에서 설명한 해제작업을 하지 않으면 메모리 누수 현상이 발생해서 웹브라우저의 작동이 멈추기도 함.
*/
componentWillUnmount() {
console.log('componentWillUnmount 호출!');
}
/** getSnapshotBeforeUpdate(prevProps, prevState)
* 1. 컴포넌트의 변경된 내용이 가상 화면에 완성된 이후 호출되는 함수이다.
* 2. 컴포넌트가 화면에 실제로 출력되기 전에 호출되므로 화면에 출력될 엘리먼트의 크기 또는 스크롤 위치 등의 DOM정보에 접근할 때 사용된다.
*/
getSnapshotBeforeUpdate() {
console.log('getSnapshotBeforeUpdate 호출!');
return {};
}
/** shouldComponentUpdate(nextProps, nextState) 함수
* 1. 프로퍼티를 변경하거나 setState() 함수를 호출하여 state값을 변경하면 '화면을 새로 출력해야 하는지' 판단하는 함수
* 2. 화면을 새로 출력할지 말지 판단하며, 데이터 변화를 비교하는 작업을 포함한다.
* 3. 2.의 이유로 리액트 성능에 영향을 많이 끼친다.
* 4. 화면 변경을 위해 검증 작업이 필요한 경우 이 함수를 사용하면 된다.
*/
shouldComponentUpdate() {
console.log('shouldComponentUpdate 호출!');
return true;
}
/** render()
* 1. 데이터가 변경되어 새 화면을 그려야 할 때 자동으로 호출되는 함수이다.
* 2. 함수가 반환하는 JSX(javaScriptXml)를 화면에 그려준다.
*/
render() {
console.log('render 호출!');
return null;
}
}
export default LifeCycleExample;
위 코드를 실행해보면 컴포넌트 생명주기에서 '생성과정'의 생명주기 함수 실행과정을 살펴 볼 수 있다.
'갱신과정'을 확인하려면 생성과정의 마지막 단계인 componentDidMount() 함수에서 state를 변경해주면 된다. (이 때 변경 과정은 shouldComponentUpdate 함수의 반환 값이 true인 경우 진행된다.)
...
componentDidMount() {
console.log('componentDidMount 호출!');
this.setState({ updated: true });
}
...
위의 코드 변경 후에는 생명주기의 '갱신과정'까지 모두 확인 할 수 있다.
shouldComponentUpdate 함수의 return 값이 false 일 때는?
...
shouldComponentUpdate() {
console.log('shouldComponentUpdate 호출!');
return false;
}
....
return 값이 false면 리액트 엔진에서 변경 사항이 없다라고 판단하기 때문에 이후 변경 과정의 생명주기 함수는 실행 되지 않는다.
만약, shouldComponentUpdate의 리턴 값에 상관 없이 화면 동기화 과정을 실행하고 싶다면 forceUpdate()함수를 사용하면 된다.사용법은 아래와 같이 변경 해주면 된다.
...
componentDidMount() {
console.log('componentDidMount 호출!');
//this.setState({ updated: true });
this.forceUpdate();
}
...
위와 같이 변경 후 실행해보면 변경 과정의 생명주기 함수가 모두 실행된다. (shouldComponentUpdate 건너 뛰고 실행됨.)
'소멸 과정'의 생명주기 함수들을 실행해보려면 아래 삼항 연산자를 App컴포넌트에 추가해주면 된다.
import React from 'react';
import LifeCycleExample from './childCom/LifeCycleExample';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { hasDestroyed: false };
}
componentDidMount() {
this.setState({ hasDestroyed: true});
}
render(){
return (
<div>
<div>
{this.state.hasDestroyed? null : <LifeCycleExample />}
</div>
</div>
);
}
}
export default App;
실행해보면 소멸 과정에 호출되는 componentWillUnmount() 함수까지 호출 됨을 알 수 있다.