리액트의 라이프사이클(LifeCycle)
- 리액트의 각 컴포넌트는 생성되고 사라지는 일련의 생애주기(LifeCycle)를 가집니다.
- 단, 라이프 사이클은 리액트의 컴포넌트 중 클래스형 컴포넌트에만 적용 가능합니다.
- 함수형 컴포넌트는 Hook을 통해 얼추 이 라이프 사이클을 흉내낼 수는 있지만, 기본적으로 라이프 사이클은 클래스형 컴포넌트에서 사용 가능합니다.
리액트의 라이프사이클 흐름도(Life Cycle’s Flow)
- 리액트는 크게 마운트 - 업데이트 - 언마운트 의 흐름을 따른다고 설명합니다.
- 마운트는 리액트 컴포넌트가 화면에 등장할 때 한 번 동작하는 단계로, constructor 등으로 state를 설정하는 등의 작업을 하는 단계입니다.
- 업데이트는 컴포넌트의 input 상자에 값이 바뀐다거나, 클릭 이벤트로 리렌더링 하는 등의 경우에 거치는 단계로, 컴포넌트가 화면에서 완전히 사라진 것이 아니면 데이터가 바뀌거나 입력값을 받는 등 거의 대부분의 상호 작용에 대응할 수 있기 때문에 리액트의 컴포넌트 생애 주기 중에서 가장 많은 시간을 점유하는 단계 입니다.
- 언마운트는 리액트 컴포넌트가 화면에서 사라질 경우 거치는 단계로 이 단계를 거치면 리액트 컴포넌트의 라이프 사이클은 종료 됩니다.
마운트(Mount, Mounting)
마운트 단계의 메서드
constructor
constructor(props){
super(props);
console.log('constructor');
}
- 생성자 메서드
- 초기 state의 값을 설정 해주는 데 사용합니다.
render
render() {
console.log('render');
const style = {
color:this.props.color,
}
return(
<>
<div className="sample">
</div>
</>
)
}
- 리액트 라이프 사이클의 모든 메서드 중에서 유일하게 필수 메서드 입니다.
- 이 메서드 안에서는 이벤트 설정이 아닌 곳에서 setState를 사용하면 안됩니다.
- 브라우저에 DOM에도 접근 할 수 없습니다.
- DOM 정보를 가져오거나 state에 변화를 주고 싶을 때는 componentDidMount에서 처리해야 합니다.
getDerivedSateFromProps
static getDerivedStateFromProps(nextProps, prevProps){
console.log("getDerivedSateFromProps");
if(nextProps.color !== prevProps.color){
return {color:nextProps.color}
}
return null;
}
- 리액트 v16.3 이후 도입된 기능입니다.
- props로 받아온 값을 state에 동기화 시키는 용도로 사용됩니다.
componentDidMount
componentDidMount(){
console.log('componentDidMount');
}
- 컴포넌트를 만들고 첫 렌더링을 다 마친 후의 상태입니다.
- 다른 자바스크립트 라이브러리, 프레임워크 함수, 이벤트 등록, setTimeout, setInterval, 네트워크 요청 같은 비동기 작업을 처리하는 데 쓰입니다.
업데이트(Update, Updation)
업데이트 단계의 메서드
shouldComponentUpdate(nextProps, nextState) { . . . }
shouldComponentUpdate(nextProps, nextState){
console.log('shouldComponentUpdate', nextProps, nextState);
return nextState.number % 10 !== 4; // 끝자리가 4일 때는 렌더링 안함.
}
- props, state 변경 시 리렌더링 시작할 지 지정하는 메서드입니다.
- 반드시 boolean 값을 리턴 해야 하며, 리액트 페이지의 전체 오류가 발생(백지현상)합니다.
getSnapshotBeforUpdate(prevProps, prevState) { . . . }
getSnapshotBeforeUpdate(prevProps, prevState){
console.log('getSnapshotBeforeUpdate');
if(prevProps.color !== this.props.color){
return this.myRef.style.color;
}
return null;
}
- 리액트 v16.3. 이후 등장하였습니다.
- render에서 만들어진 결과물이 실제 반영되기 직전에 호출합니다.
- compoentDidUpdate 이전 메서드이므로 이 단계에서 리턴하는 값이 compoentDidUpdate 메서드의 snapshot 매개변수가 됩니다.
- 업데이트하기 직전의 값을 참고하는데 주로 사용되며 대표적으로 스크롤바 위치 유지 등에 응용됩니다.
componentDidUpdate(prevProps, prevState, snapshot) { . . . }
componentDidUpdate(prevProps, prevState, snapshot){
console.log('componentDidUpdate', prevProps, prevState, snapshot);
if(snapshot){
console.log('업데이트 직전의 색상 :', snapshot);
}
}
- 리렌더링 완료 후 실행합니다.
- 업데이트 직후이므로 DOM 관련 처리가 가능합니다.
- prevProps또는 prevState에 접근하여 컴포넌트가 이전에 가졌던 데이터에 접근 가능합니다.
- getSnapshotBeforUpdate에서 리턴한 값이 있다면 snapshot 변수로 받아 사용 가능합니다.
언마운트(UnMount, UnMounting)
언마운트 단계의 메서드
componentWillUnmount
componentWillUnmount(){
console.log('componentWillUnmount');
}
- 컴포넌트를 DOM에서 제가할 때 실행합니다.
- componentDidMount에서 생성한 DOM, event 등이 있다면 제거해야 합니다.
에러 (Error)
- 컴포넌트의 일반적인 라이프 사이클은 아닙니다.
- 컴포넌트에서 오류를 감지하면 캐치하고 오류 페이지를 렌더링하는데 응용 가능합니다.
compoentDidCatch
- 컴포넌트의 예외 처리를 담당합니다.
- 실제 렌더링 되는 컴포넌트에서 해당 메서드를 사용하면 에러를 잡을 수 없습니다.
- 이 메서드를 사용하면 부모 컴포넌트에서 넘겨주는 children 프로퍼티를 통해 오류를 검출하므로, 예외 처리를 원하면 별도의 예외처리 담당 컴포넌트를 작성하고 실제 렌더링 될 컴포넌트를 감싸는 식으로 코드를 작성해야 합니다.
에러 핸들링 컴포넌트는 아래와 같이 작성할 수 있습니다.
import { Component } from "react";
class ErrorHandlingComp extends Component {
state = {
isError: false,
};
componentDidCatch(error, info) {
this.setState({
isError: true,
});
console.log({ error, info });
}
render() {
if (this.state.isError) return <div className="error-div">에러가 발생했습니다.</div>;
return this.props.children;
}
}
export default ErrorHandlingComp;
App.js (부모 컴포넌트) 에서 에러를 핸들링 하도록 작성합니다.
import './App.css';
import './asset/Custom.css';
import './asset/LifeCycleComp.css'
import {Fragment, Component} from "react";
import LifeCycleComp01 from "./components/LifeCycleComp01";
import ErrorHandlingComp from './components/ErrorHandlingComp';
function getRandomColor() {
return '#' + Math.floor(Math.random()*16777215).toString(16);
}
class App extends Component {
state = {
color :'#000000',
name : 'LifeCycle'
}
handleClick = () => {
this.setState({
color:getRandomColor()
});
}
render() {
const {name} = this.state;
return(
<>
<div className="main-header">
<p>React의 <span>{name}</span> 에 대해 알아보기</p>
<button onClick={this.handleClick}>랜덤 색상</button>
</div>
<ErrorHandlingComp>
<LifeCycleComp01 color={this.state.color} />
</ErrorHandlingComp>
</>
)
}
}
export default App;
- 오류 발생 시 렌더링 된 페이지
클래스형 컴포넌트의 라이프사이클 적용 예시
import { Fragment, Component } from "react";
class LifeCycleComp01 extends Component{
state = {
number: 0,
color:null,
}
myRef = null; // ref를 설정하기 위한 부분
constructor(props){
super(props);
console.log('constructor');
}
static getDerivedStateFromProps(nextProps, prevProps){
console.log("getDerivedSateFromProps");
if(nextProps.color !== prevProps.color){
return {color:nextProps.color}
}
return null;
}
componentDidMount(){
console.log('componentDidMount');
}
shouldComponentUpdate(nextProps, nextState){
console.log('shouldComponentUpdate', nextProps, nextState);
return nextState.number % 10 !== 4; // 끝자리가 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, snapshot);
if(snapshot){
console.log('업데이트 직전의 색상 :', snapshot);
}
}
render() {
console.log('render');
const style = {
color:this.props.color,
}
return(
<>
<div className="comp class-comp life-comp">
<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>
</div>
</>
)
}
}
export default LifeCycleComp01;
- 실제 렌더링된 페이지 모습
'프론트엔드(Front-End) > React' 카테고리의 다른 글
[REACT] 리액트와 라우터(Router) (2) | 2023.01.09 |
---|---|
[REACT] 리액트와 훅(HOOK) (0) | 2023.01.08 |
[REACT] 컴포넌트 요소의 반복(map, filter) (0) | 2023.01.06 |
[REACT] 리액트의 ref (0) | 2023.01.05 |
[REACT] 리액트와 EVENT (0) | 2023.01.04 |