LifeCycle Method 는 '생명주기 메서드' 라고 부른다.
컴포넌트가 브라우저상에 나타나고, 업데이트 되고, 사라지게 될 때 호출되는 메서드이다.
생명주기 메서드는 클래스형 컴포넌트에서만 사용할 수 있는데, useEffect 와 비슷하다고 생각하면 된다.
앞으로 사용할 일이 별로 없을 것이므로 많은 시간을 쏟지 않길 권장하며, 다만 어떤 것들이 있는지 알아만 두고 나중에 사용해야 할 일이 있다면 메뉴얼을 보고 사용할 수 있을 정도로만 학습하면 된다.
마운트
마운트될 때 발생하는 생명주기
- constructor : 컴포넌트가 만들어지면 가장 먼저 실행되는 메서드 (생성자 메서드)
- getDrivedStateFromProps : props 로 받아온 것을 state 에 넣어주고 싶을 때 사용
- render : 컴포넌트를 렌더링하는 메서드
- componentDidMount : 컴포넌트의 첫번째 렌더링이 마치고 나면 호출되는 메서드
Constructor
컴포넌트의 생성자 메서드로, 컴포넌트가 만들어지면 가장 먼저 실행되는 메서드이다.
constructor(props) {
super(props);
console.log("constructor");
}
getDerivedStateFromProps
props 로 받아온 것을 state 에 넣어주고 싶을 때 사용한다.
다른 생명주기 메서드와는 달리 앞에 static 을 필요로 하고, 이 안에서는 this 를 조회할 수 없다.
특정 객체를 반환하게 되면 해당 객체 안에 있는 내용들이 컴포넌트의 state 로 설정된다.
null 을 반환하게 되면 아무일도 발생하지 않는다.
** 컴포넌트가 처음 렌더링 되기 전에도 호출되고, 그 이후 리렌더링 되기 전에도 매번 실행된다.
static getDerivedStateFromProps(nextProps, prevState) {
console.log("getDerivedStateFromProps");
if (nextProps.color !== prevState.color) {
return { color: nextProps.color };
}
return null;
}
render
컴포넌트를 렌더링하는 메서드
componentDidMount
컴포넌트의 첫번째 렌더링이 마치고 나면 호출되는 메서드이다.
메서드가 호출되는 시점에는 컴포넌트가 화면에 나타난 상태이다.
주로 D3, masonry 처럼 DOM을 사용해야 하는 외부 라이브러리 연동을 하거나, 해당 컴포넌트에서 필요로 하는 데이터를 요청하기 위해 axios, fetch 등을 통하여 ajax 요청을 하거나, DOM의 속성을 읽거나 직접 변경하는 작업을 진행한다.
업데이트
컴포넌트가 업데이트 되는 시점에 호출되는 메서드
- getDerivedStateFromProps : 컴포넌트의 props 나 state 가 바뀌었을 때 호출되는 메서드
- shouldComponentUpdate : 컴포넌트가 리렌더링 할지 말지 결정하는 메서드
- render
- getSnapshotBeforeUpdate : 브라우저에 변화를 일으키기 직전에 호출되는 메서드
- componentDidUpdate : 리렌더링이 마치고 화면에 변화가 반영된 뒤 호출되는 메서드
shouldComponentUpdate
컴포넌트가 리렌더링 할지 말지 결정하는 메서드
주로 최적화 할 때 사용하는 메서드 (React.memo 의 역할과 비슷)
shouldComponentUpdate(nextProps, nextState) {
console.log("shouldComponentUpdate", nextProps, nextState);
// 숫자의 마지막 자리가 4면 리렌더링하지 않습니다
return nextState.number % 10 !== 4;
}
getSnapshotBeforeUpdate
컴포넌트에 변화가 일어나기 직전의 DOM 상태를 가져와서 특정 값을 반환하면 그 다음 발생하게 되는 componentDidUpdate 함수에서 받아와서 사용할 수 있다.
함수형 컴포넌트 + Hooks 를 사용할 때에는 getSnapshotBeforeUpdate 를 대체 할 수 있는 기능이 아직 없다.
DOM 에 변화가 반영되기 직전에 DOM 의 속성을 확인하고 싶을 때 이 메서드를 사용하면 된다.
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate");
if (prevProps.color !== this.props.color) {
return this.myRef.style.color;
}
return null;
}
componentDidUpdate
리렌더링이 마치고 화면에 변화가 반영된 뒤 호출되는 메서드
3번째 파라미터로 getSnapshotBeforeUpdate 에서 반환한 값을 조회할 수 있다.
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate", prevProps, prevState);
if (snapshot) {
console.log("업데이트 되기 직전 색상: ", snapshot);
}
}
언마운트
컴포넌트가 화면에서 사라질 때 언마운트와 관련된 생명주기 메서드
- componentWillUnmount : 컴포넌트가 화면에서 사라지기 직전에 호출된다.
componentWillUnmount
컴포넌트가 화면에서 사라지기 직전에 호출된다.
주로 DOM에 직접 등록했었던 이벤트를 제거하고, setTimeout 을 걸은 것이 있다면 clearTimeout 을 통하여 제거한다.
외부 라이브러리를 사용한게 있고 해당 라이브러리에 dispose 기능이 있다면 여기서 호출해주면 된다.
componentWillUnmount() {
console.log("componentWillUnmount");
}
componentDidCatch
리액트 앱에서 에러가 발생하는 상황
: 흰 화면을 보여주는 대신에 에러가 발생했다는 것을 알려주는 방법
componentDidCatch(error, info) {
console.log('에러가 발생했습니다.');
console.log({
error,
info
});
error 는 에러 정보를 받아오고, info 는 에러가 발생한 위치를 알려준다.
import React, { Component } from 'react';
class ErrorBoundary extends Component {
state = {
error: false // 기본 state: false
};
componentDidCatch(error, info) {
console.log('에러가 발생했습니다.');
console.log({
error,
info
});
this.setState({
error: true // error 가 발생하면 true
});
}
render() {
if (this.state.error) { // state 가 true일 때 에러발생 문구 출력
return <h1>에러 발생!</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
Sentry
componentDidCatch 를 사용해서 앱에서 에러가 발생했을 때 사용자에게 에러가 발생했음을 인지시켜줄 수 있지만, componentDidCatch 가 실제로 호출되는 일은 서비스에서 없어야 한다.
사용자가 발견하게 되는 오류들은 componentDidCatch 에서 error 와 info 값을 네트워크를 통하여 다른 곳으로 전달해주면 된다.
Sentry 라는 상용서비스를 통해서 에러가 발생하면 실시간으로 모니터링을 받을 수 있다.
장기적으로 작업하는 프로젝트에 적용하는 것을 권장한다.
Sentry 적용법
프로젝트 디렉터리에서 설치
$ yarn add @sentry/browser
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as Sentry from '@sentry/browser';
import * as serviceWorker from './serviceWorker';
Sentry.init({
dsn: 'https://87fba3b585d940f58806848807325ffb@sentry.io/1493504'
});
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
Sentry.init( )을 사용할 때에는 dsn 값은 프로젝트마다 다르니 각자의 dsn 값을 넣어준다.
적용 후 실시간 확인
🚨 주의!!
여기서 끝이 아니라 이렇게 에러가 발생했을 때 sentry 쪽으로 전달되는 것은 개발모드일 땐 별도의 작업을 하지 않아도 되지만, 나중에 프로젝트를 완성하여 실제 배포를 하게 됐을 때는 componentDidCatch 로 이미 에러를 잡아줬을 경우 Sentry 에게 자동으로 전달되지 않는다.
때문에 ErrorBoundary 에서 다음과 같이 처리해주어야 한다.
import React, { Component } from 'react';
import * as Sentry from '@sentry/browser';
class ErrorBoundary extends Component {
state = {
error: false
};
componentDidCatch(error, info) {
console.log('에러가 발생했습니다.');
console.log({
error,
info
});
this.setState({
error: true
});
if (process.env.NODE_ENV === 'production') { // 작성
Sentry.captureException(error, { extra: info });
}
}
render() {
if (this.state.error) {
return <h1>에러 발생!</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
프로덕션 환경에서 잘 작동하는지 확인하기
프로덕션 환경에서도 잘 작동하는지 확인하기 위해서는 프로젝트를 빌드해주어야 한다.
프로젝트 디렉터리에서 다음 명령어를 실행한다.
$ yarn build
결과물이 build 디렉터리에 나타난다.
build 디렉터리에 있는 파일들을 제공하는 서버를 실행하기 위해서는 다음 명령어를 실행한다.
$ npx serve ./build
serve 는 웹서버를 열어서 특정 디렉터리에 있는 파일을 제공해주는 도구이다.