모든 리액트 컴포넌트는 라이프사이클(수명 주기)이 존재합니다. 컴포넌트의 수명은 페이지에 렌더링 되기 전, 준비 과정에서 시작하여 페이지가 사라질 때 끝납니다.
컴포넌트의 라이프사이클 메서드를 사용하는 경우는 다음과 같습니다.
라이프사이클 메서드는 클래스형 컴포넌트에서만 사용 가능합니다. 함수 컴포넌트에서는 Hooks 기능을 사용하여 비슷한 작업을 처리할 수 있습니다.
라이프사이클 메서드의 종류는 총 9가지입니다.
라이프사이클은 총 3가지 카테고리로 나뉩니다.
마운트, 업데이트, 언마운트 카테고리를 간단히 알아보고 큰 흐름을 먼저 이해해봅시다.
DOM이 생성되고 웹 브라우저상에 나타나는 것을 마운트(mount)라고 합니다.
컴포넌트는 다음과 같은 4가지 경우에 업데이트를 진행하게 됩니다.
컴포넌트가 업데이트되면 다음 메서드를 호출하는 과정을 거칩니다.
마운트의 반대 과정으로 컴포넌트를 DOM에서 제거하는 것을 언마운트(unmount)라고 합니다.
render() { ... }
constructor(props) { ... }
static getDerivedStateFromProps(nextProps, prevState) {
if(nextProps.value !== prevState.value) { // 조건에 따라 특정 값 동기화
return { value: nextProps.value };
}
return null; // state를 변경할 필요가 없다면 null을 반환
}
componentDidMount() { ... }
shouldComponentUpdate(nextProps, nextState) { ... }
getSnapshotBeforeUpdate(prevProps, prevState) {
if(prevState.array !== this.state.array) {
const { scrollTop, scrollHeight } = this.list
return { scrollTop, scrollHeight };
}
}
componentDidUpdate(prevProps, prevState, snapshot) { ... }
componentWillUnmount() { ... }
componentDidCatch(error, info) {
this.setState({
error: true
});
console.log({ error, info });
}
배운 라이프사이클 메서드를 다음 단계별로 사용해봅시다.
// LifeCycleSample.js
import { 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');
// 숫자의 마지막 자리가 4면 리렌더링하지 않음
return nextState.number % 10 !== 4;
}
componentWillUnount() {
console.log('componentWillUnount');
}
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;
// App.js
import { Component } from "react";
import LifeCycleSample from "./LifeCycleSample";
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
class App extends Component {
state = {
color: '#000000'
}
handleClick = () => {
this.setState({
color: getRandomColor()
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>랜덤 색상</button>
<LifeCycleSample color={this.state.color}/>
</div>
);
}
}
export default App;
이 코드의 실행 결과는 다음과 같습니다.
라이프사이클 메서드를 실행시키면 다음과 같은 결과를 낼 수 있을 것입니다.
LifeCycleSample 컴포넌트의 render 함수에서 에러가 발생했을 때 처리를 배워봅시다. render 함수에서 에러는 1)존재하지 않는 함수를 사용하려 하거나, 2)존재하지 않는 객체의 값을 조회하려 할 때 발생합니다.
의도적으로 render에서 존재하지 않는 props인 missing 객체 값을 조회하도록 코드를 변경해봅시다.
// LifeCycleSample.js
(...)
render() {
console.log('render');
const style = {
color: this.props.color
};
return (
<div>
{this.props.missing.value}
<h1 style={style} ref={ref => this.myRef=ref}>
{this.state.number}
</h1>
<p>color: {this.state.color}</p>
<button onClick={this.handleClick}>
더하기
</button>
</div>
)
}
에러를 잡아주는 ErrorBoundary 컴포넌트를 작성해봅시다.
// ErrorBoundary.js
import { Component } from "react";
class ErrorBoundary extends Component {
state = {
error: false
};
componentDidCatch(error, info) {
this.setState({
error: true
});
console.log({ error, info });
}
render() {
if( this.state.error ) return <div>에러가 발생했습니다.</div>
return this.props.children;
}
}
export default ErrorBoundary;
App.js에서는 LifeCycleSample 컴포넌트를 감싸줍니다.
// App.js
import { Component } from "react";
import LifeCycleSample from "./LifeCycleSample";
import ErrorBoundary from "./ErrorBoundary"
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
class App extends Component {
state = {
color: '#000000'
}
handleClick = () => {
this.setState({
color: getRandomColor()
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>랜덤 색상</button>
<ErrorBoundary>
<LifeCycleSample color = {this.state.color} />
</ErrorBoundary>
</div>
);
}
}
export default App;
코드를 작성하고 저장하면 다음과 같은 문구를 확인할 수 있습니다.
컴포넌트의 라이프사이클 메서드 흐름은 다음과 같습니다.
// App.js
import { Component } from "react";
import LifeCycleSample from "./LifeCycleSample";
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
class App extends Component {
state = {
color: '#000000'
}
handleClick = () => {
this.setState({
color: getRandomColor()
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>랜덤 색상</button>
<LifeCycleSample color={this.state.color}/>
</div>
);
}
}
export default App;
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
9.
// App.js
import { Component } from "react";
import LifeCycleSample from "./LifeCycleSample";
import ErrorBoundary from "./ErrorBoundary" //수정
function getRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16);
}
class App extends Component {
state = {
color: '#000000'
}
handleClick = () => {
this.setState({
color: getRandomColor()
});
}
render() {
return (
<div>
<button onClick={this.handleClick}>랜덤 색상</button>
<ErrorBoundary> //수정
<LifeCycleSample color = {this.state.color} />
</ErrorBoundary>
</div>
);
}
}
export default App;
◎ 다라
[리액트스타터2] 9장. 컴포넌트 스타일링 (0) | 2022.12.01 |
---|---|
[리액트스타터2] 8장. Hooks (0) | 2022.11.24 |
[리액트스타터2] 6장. 컴포넌트 반복 (0) | 2022.11.10 |
[리액트스타터2] 5장. ref (0) | 2022.11.05 |
[리액트스타터2] 4장. 이벤트 핸들링 (0) | 2022.10.13 |