라이프사이클이란?
- 리액트 컴포넌트는 생명을 가지고 있는데, 이 생명의 주기는 페이지에 렌더링되기 전인 준비 과정에서 시작하여 페이지에서 사라질 때 끝난다
- 이러한 수명(생명 주기)을 간단하게 3부분으로 나누어서 각각 파트에서 불러오는 메서드들을 라이프사이클 메서드라고 부른다
- 라이프사이클 메서드는 클래스형 컴포넌트에서만 사용이 가능하다
7-1. 라이프사이클 메서드의 이해
라이프사이클 메서드의 종류는 총 9가지이다
- Will 접두사가 붙은 메서드 : 작업하기 전에 실행되는 메서드
- Did 접두사가 붙은 메서드 : 작업을 한 후에 실행되는 메서드
그리고 위에서 말했듯이 수명을 3가지 부분으로 나누는데
- 마운트 : DOM이 생성되고 웹 브라우저상에 나타나는 것
- 업데이트 : 컴포넌트의 정보가 바뀌어서 리렌더링될 때
- 언마운트 : DOM에서 컴포넌트를 제거하는 것
7-1-1. 마운트
마운트 단계에서 호출하는 메서드는 다음과 같다
- constructor : 컴포넌트를 새로 만들 때마다 호출되는 생성자 메서드
- getDerivedStateFromProps : props에 있는 값을 state와 동기화시킬 때 호출하는 메서드
- render : 우리가 JSX로 작성한 View를 렌더링하는 메서드
- componentDidMount : 컴포넌트가 웹 브라우저상에 나타난 후 호출되는 메서드
7-1-2. 업데이트
컴포넌트는 다음과 같은 경우에 업데이트한다
- props나 state가 바뀔 때
- 부모 컴포넌트가 리렌더링될 때
- this.forceUpdate로 강제로 렌더링을 트리거할 때
이렇게 업데이트되면 리렌더링되면서 다음과 같은 메서드들을 호출한다
- getDerivedStateFromProps : props값의 변화에 따라 state의 값에 변화를 줄 때 사용하는 메서드
- shouldComponentUpdate : 이 메서드에서 true를 반환하면 다음 단계로 진행, false를 반환하면 작업을 중지시켜 리렌더링을 멈춘다 다른 함수에서 this.forceUpdate를 호출하면 이 단계는 생략된다
- render : 컴포넌트를 리렌더링한다
- getSnapShotBeforeUpdate : 컴포넌트의 변화를 DOM에 반영하기 바로 직전에 호출하는 메서드
- componentDidUpdate : 컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드
7-1-3. 언마운트
- componentWillUnmount : 웹 브라우저상에서 사라지기 전에 호출하는 메서드
7-2. 메서드 살펴보기
위에서 나열한 메서드 중 몇가지만 살펴보자
7-2-1. getDerivedStateFromProps 메서드
static getDerivedStateFromProps(nextProps, prevState){
// 조건에 맞추어서 값을 동기화
if(nextProps.value !== prevState.value){
return {value : nextProps.value};
}
// 변경하지 않으면 null
return null;
}
7-2-2. getSnapshotBeforeUpdate 메서드
이 메서드는 render에서 만들어진 결과물이 브라우저에 실제로 반영되기 직전에 호출되며 반환된 값은 후술할 componentDidUpdate에서 3번째 파라미터인 snapshot값으로 전달 받을 수 있다
getSnapshotBeforeUpdate(prevProps, prevState){
if(prevState.array !== this.state.array){
const {scrollTop, scrollHeight} = this.list;
return {scrollTop, scrollHeight};
}
}
7-2-3. componentDidUpdate 메서드
getSnapshotBeforeUpdate(preProps, preState, snapShot){}
업데이트가 끝난 직후이므로 DOM 관련 처리를 해도 무방하다
prevProps, prevState를 이용하여 컴포넌트가 가졌던 데이터에 접근할 수 있으며 getSnapshotBeforeUpdate에서 반환한 값을 snapshot으로 전달받을 수 있다
7-2-4. componentDidCatch 메서드
컴포넌트 렌더링 도중에 에러가 발생했을 경우 먹통을 방지하고 오류 UI를 볼 수 있게 해준다
componentDidCatch(error, info){
this.setState({
error : true,
});
console.log({error, info});
}
error는 어떤 오류가 발생했는지 info는 어느 코드에서 발생했는지에 대한 정보를 알려준다
7-3. 라이프사이클 메서드 사용하기
import React, { Component } from 'react';
class LifeCycleSample extends Component {
state = {
number: 0,
color: null
};
myRef = null; // ref를 설정할 부분
constructor(props) {
super(props);
console.log('constructor');
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log('getDerivedStateFromProps');
if (nextProps.color !== prevState.color) {
return { color: nextProps.color };
}
return null;
}
componentDidMount() {
console.log('componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
console.log('shouldComponentUpdate', nextProps, nextState);
// 숫자의 마지막 자리가 4면 리렌더링하지 않습니다.
return nextState.number % 10 !== 4;
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
handleClick = () => {
this.setState({
number: this.state.number + 1
});
};
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('getSnapshotBeforeUpdate');
if (prevProps.color !== this.props.color) {
return this.myRef.style.color;
}
return null;
}
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;
import React, {Component} from 'react';
class ErrorBoundary extends Component{
state = {
error : false
}
componentDidCatch(error, errorInfo) {
this.setState({
error : true
});
console.log({error, errorInfo});
}
render(){
return this.state.error ? <div>에러가 발생했습니다</div> : <div>{this.props.children}</div>
}
}
export default ErrorBoundary;
import React, {Component} from "react";
import LifeCycleSample from './LifeCycleSample';
import ErrorBoundary from './ErrorBoundary';
function randomColor() {
return "#" + Math.random().toString(16).slice(2,8);
}
class App extends Component{
state = {
color : `#000000`,
}
render (){
return (
<div>
<button onClick={this.handleClick}> 색상 업데이트 </button>
<ErrorBoundary>
<LifeCycleSample color={this.state.color}/>
</ErrorBoundary>
</div>
)
}
handleClick =()=> {
this.setState({
color : randomColor()
});
}
}
export default App;
'React > 리액트를 다루는 기술' 카테고리의 다른 글
9. 컴포넌트 스타일링 (0) | 2021.01.25 |
---|---|
8. Hooks (0) | 2021.01.22 |
6. 컴포넌트 반복 (0) | 2021.01.17 |
5. ref: DOM에 이름 달기 (0) | 2021.01.15 |
4. 이벤트 핸들링 (0) | 2021.01.12 |