React 생명주기 이벤트
리엑트에서 사용되는 클래스에서도 일반 객체 지향에서 쓰이는 클래스와 동일하게 Life Cycle이 존재합니다.
많은 컴포넌트가 사용되는 애플리케이션은 리소스나 메모리를 많이 차지하기 때문에 이런 리소스나 메모리를 관리하기 위해 컴포넌트가 삭제될 때 사용중이던 리소스를 반환해주는 것이 중요합니다.
리엑트에서는 클래스가 DOM에 렌더링 될 때, 혹은 삭제 될 때 등과 같은 생명주기 이벤트가 존재합니다.
예를 들어 현재 시간을 표시해주는 기능을 구현한다고 합니다.
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
단순하게 function을 사용하는 경우입니다. 하지만 함수 형태가 아닌 클래스의 형태로 사용할 때가 있습니다.
직관적으로 위의 코드를 클래스 형태로 변환 한다면 아래와 같이 되겠습니다.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
함수에서 사용된 setInterval로 매초 업데이트되던 시간을 클래스에서도 적용하기 위해서는 앞서 설명한 생명주기 이벤트를 사용해야 합니다.
리엑트에서는 컴포넌트가 DOM에 렌더링 될 때를 마운팅 된다고 표현하고, componentDidMount()라는 함수를 사용합니다.
반대로 컴포넌트에 의해 생성된 DOM이 삭제 될 때 언마운팅 된다고 표현하고 componentWillUnmount()라는 함수를 사용합니다.
이러한 함수들을 생명주기 메서드라고 합니다.
이러한 생명주기 메서드를 사용해서 매초 시간을 업데이트 하도록 코드를 작성하게 되면 아래와 같이 작성할 수 있습니다.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
앞에서 설명했던 setState()함수로 인해 현재 state에 따라 변경된 값으로 UI가 렌더링 되며 시간이 매초마다 업데이트 되는 것을 확인할 수 있습니다.
이 setState()호출로 인해 React에서 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기 위해 render()메서드를 다시 호출하는데, 이런 과정으로 React는 DOM을 업데이트합니다.
componentDidMount에서 timerID에 setInterver함수를 초기화 했으니, 컴포넌트가 삭제될 때는 이 timerID를 clearInterval()함수로 같이 삭제해주는 것으로 리소스를 관리합니다.
전체적인 생명주기 이벤트 흐름
import React, { Component } from 'react';
class Counter extends Component {
state = {
number: 0
}
constructor(props) {
super(props);
console.log('constructor');
}
componentWillMount() {
console.log('componentWillMount (deprecated)');
}
componentDidMount() {
console.log('componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
// 5 의 배수라면 리렌더링 하지 않음
console.log('shouldComponentUpdate');
if (nextState.number % 5 === 0) return false;
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate');
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate');
}
handleIncrease = () => {
const { number } = this.state;
this.setState({
number: number + 1
});
}
handleDecrease = () => {
this.setState(
({ number }) => ({
number: number - 1
})
);
}
render() {
console.log('render');
return (
<div>
<h1>카운터</h1>
<div>값: {this.state.number}</div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
}
export default Counter;
전체적인 생명주기 이벤트 흐름을 작성한 코드를 가지고 왔는데요, 5의 배수일 때는 카운터가 작동하지 않는 코드입니다.
컴포넌트가 렌더링 되기 전에 제일 먼저 생성자가 호출 되고, 그 다음에 WillMount(렌더링 되기 직전), Render, ComponentDidMount(컴포넌트 렌더링 완료) 이런 순서로 진행이 됩니다.
또한 버튼 이벤트가 작동했을 때의 순서도 파악해주시면 좋습니다!
'FrontEnd > React 기본' 카테고리의 다른 글
[React] React.js 강좌 6. Error Catch (0) | 2021.11.25 |
---|---|
[React] React.js 강좌 5. 이벤트 처리, Bind (0) | 2021.11.19 |
[React] React.js 강좌 3. Fragments (0) | 2021.11.18 |
[React] React.js 강좌 2. 클래스형 Props & State 정리 (2) | 2021.11.15 |
[React] React.js 강좌 1. 기초 개념 정리 (2) | 2021.11.12 |