컴포넌트가 브라우저 상에 나타날 때, 업데이트 될 때, 사라질 때 이 중간 과정에서 어떤 작업을 수행하고자 할 때 LifeCycle API를 사용한다.
mounting이란 컴포넌트가 브라우저 상에 나타나는 것이다.
mounting 함수들
constructor
: 생성자 함수, 컴포넌트가 브라우저에 처음 나타날 때 가장 먼저 실행되는 함수이다. 여기에서는 보통 컴포넌트가 가지는 state나 미리 수행해야 하는 작업을 넣어준다.
getDerivedStateFromProps
: props로 받은 값을 state로 동기화하고자 할 때 사용된다. (updating과정에서도 props가 바뀔 때 이 함수가 실행된다.)
render
: 어떤 돔을 만들게 되고 내부의 태그는 어떤 값을 전달해줄지 정의.
componentDidMount
: 주로 외부 라이브러리를 사용할 때 이 함수에서 특정 돔에 차트를 그려달라고 요청할 수 있다. 또는 ajax요청을 처리할 때 이 함수에서 처리한다. 또 컴포넌트가 나타나도 몇초 후에 이벤트를 하고싶다와 같은 이벤트를 처리할 때에도 사용된다. 즉 컴포넌트가 브라우저에 나타나고 어떤 시점에 작업을 주고자 할 때 명시해주는 함수이다.
컴포넌트의 props나 state가 바뀌었을 때를 나타낸다.
getDerivedStateFromProps
: Mounting에서 쓰이는 함수와 같다. props의 값을 state에 동기화 시킬 때 사용
shouldComponentUpdate
: 컴포넌트가 업데이트되는 성능을 최적화시킬 때 사용한다. 컴포넌트는 기본적으로 부모 컴포넌트가 업데이트될 때 자식컴포넌트도 모두 렌더함수가 작동한다. 그러나 가상 돔에서 공부했다시피 컴포넌트가 변경되는 영역만 리렌더되는 것이 렌더링 과정이 빠르다는 장점이 있는 건데 부모 컴포넌트가 렌더될 때 자식도 렌더되면 눈에는 안보여도 리렌더가 되어 가상 돔에 적용되고 있다는 것이다. 부모 컴포넌트의 변화를 자식 컴포넌트에도 적용해야할 때는 이것이 필요한 기능이고 장점이지만 그럴 필요가 없을 때는 shouldComponentUpdate 를 사용해서 필요 없는 가상돔의 업데이트를 막을 수 있다.
이 함수는 true나 false값을 반환할 수 있다. true값을 반환하면 렌더링 프로세스를 거치는 것이고 false값을 반환하면 리렌더 과정을 거치지 않고 props나 state의 변화를 반영하지 않게 된다.
즉 shouldComponentUpdate 함수는 가상 돔에도 업데이트를 적용할지 말지를 결정해주는 역할을 한다.
getSnapshotBeforeUpdate
: 앞의 shouldComponentUpdate함수와 render함수를 거친 후에 실행되는 함수이다. 렌더링 이후에 그 결과물이 브라우저에 반영되기 바로 직전에 호출되는 함수이다. 렌더링 이후에 스크롤의 위치나 해당 돔의 크기를 사전에 가져오고자 할 때 사용하는 함수이다.
componentDidUpdate
: 위의 작업들을 마치고 컴포넌트가 업데이트 되었을 때 호출되는 함수이다. state가 바뀌었을 때 이전의 상태와 지금의 상태가 달라졌을 때 (예를들어 페이지가 달라졌을 때) 작업을 설정할 수 있다.
컴포넌트가 브라우저에서 사라질 때를 나타낸다.
componentWillUnmount
: 컴포넌트가 사라지는 과정에서 호출되는 함수이다. 앞의 mount과정에서 호출 되는 함수인 componentDidMount함수에서는 이벤트를 리스닝할 수 있다고 했는데 componentWillUnmount 에서는 앞에서 설정한 이벤트 리스너를 없애주는 작업을 하면 된다.
App.js
import React, { Component } from 'react';
class App extends Component {
constructor(props){ //1
super(props); //2
console.log('constructor');//3
}
render() {
return(
<div>안녕하세요</div>
);
}
}
App.js
import React, { Component } from 'react';
class App extends Component {
constructor(props){ //1
super(props); //2
console.log('constructor'); //3
}
componentDidMount() {
console.log('componentDidMount'); //4
}
render() {
return(
<div>안녕하세요</div>
);
}
}
componentDidMount 를 이용해서 돔 조작하기
App.js
import React, { Component } from 'react';
class App extends Component {
constructor(props){ //1
super(props); //2
console.log('constructor'); //3
}
componentDidMount() {
console.log('componentDidMount'); //4
console.log('this.myDiv.getBoundingClientRect()'); //6
}
render() {
return(
<div ref={ref => this.myDiv = ref}>안녕하세요</div> //5
);
}
}
ref란 DOM에 id를 붙이는것과 비슷하다. 돔에 대한 레퍼런스를 바로 가져올 수 있는 것.
ref= //ref는
{ref=>this.myDiv = ref} //ref를 파라미터로 가져오는 함수를 작성해서 설정해준다.
실행시킨 후 개발자 도구를 보면 myDiv의 각 요소들의 위치, 크기와 같은 값들을 볼 수 있다.
props를 state로 동기화시키고자 할 때 객체를 return해주면 된다. 그러면 반환된 그 객체의 값이 state로 된다.
MyComponent.js
import React, { Component } from 'react';
class MyComponent extends Component {
state = {
value: 0
};
static getDerivedStateFromProps(nextProps, prevState) { //7
if (prevState.value !== nextProps.value {
return {
value: nextProps.value //8
}
}
return null; //9
}
render() {
return (
<div>
<p>props: {this.props.value}</p>
<p>state: {this.state.value}</p>
</div>
);
}
}
export default MyComponent;
App.js
import React, { Component } from 'react';
import MyComponent from './MyComponent';
class App extends Component {
state = {
counter: 1,
}
constructor(props){
super(props);
console.log('constructor');
}
componentDidMount() {
console.log('componentDidMount');
console.log('this.myDiv.getBoundingClientRect()');
}
handleClick = () => { //10
this.setState({
counter: this.state.counter + 1
});
}
render() {
return(
<div >
<MyComponent value={this.state.counter}/>
<button onClick={this.handleClick}>Click Me</button> //10
</div>
);
}
}
getDerivedStateFromProps 는 static으로 생성해줘야한다. 파라미터로는 nextProps와 prevState 인데, nextProps 는 다음으로 받아올 props값을 가져오고, prevState 는 변경되기 전인 현재의 상태를 가져오는 것이다.
prevState와 NextProps의 값이 다를 때 nextProps의 value값으로 value를 셋팅해준다.
만약 변경사항이 없으면 그냥 비워두거나 null을 리턴해주면 된다.
props값에 변화를 줬을 때 state가 어떻게 변하는지 알아보기 위해서 추가해준 코드
버튼을 누르면 props값이 바뀌고 동시에 state값도 변하는 것을 알 수 있다.
shouldComponentUpdate를 따로 구현하지 않는다면 true를 리턴하는 해당 함수가 디폴트로 설정된다. 특정 상황에 리렌더를 하지 않도록 하기 위해 false를 리턴할 조건을 구현한 뒤 리턴값을 false로 지정해주면 된다.
즉 업데이트를 막아주는 함수로 생각해주면 된다.
MyComponent.js
import React, { Component } from 'react';
class MyComponent extends Component {
state = {
value: 0
};
static getDerivedStateFromProps(nextProps, prevState) { //7
if (prevState.value !== nextProps.value {
return {
value: nextProps.value //8
}
}
return null; //9
}
shouldComponentUpdate(nextProps, nextState) {
if (nextProps.value === 10) return false;
return true;
} //11
render() {
return (
<div>
<p>props: {this.props.value}</p>
<p>state: {this.state.value}</p>
</div>
);
}
}
export default MyComponent;
컴포넌트가 업데이트 돼서 브라우저의 돔에 반영되기 바로 직전에 호출되는 함수이다.
업데이트 되기 바로 직전의 돔 상태를 리턴해준다.
컴포넌트가 업데이트된 후에 호출되는 함수이다.
componentDidUpdate(prevProps, prevState, snapshot) {}
prevProps
: 업데이트 되기 바로 직전의 props
MyComponent.js
import React, { Component } from 'react';
class MyComponent extends Component {
state = {
value: 0
};
static getDerivedStateFromProps(nextProps, prevState) { //7
if (prevState.value !== nextProps.value {
return {
value: nextProps.value //8
}
}
return null; //9
}
shouldComponentUpdate(nextProps, nextState) {
if (nextProps.value === 10) return false;
return true;
} //11
componentDidUpdate(prevProps, prevState) {
if(this.props.value !== prevProps.value) {
colsole.log('value값이 바뀌었다!');
} //12
render() {
return (
<div>
<p>props: {this.props.value}</p>
<p>state: {this.state.value}</p>
</div>
);
}
}
export default MyComponent;
컴포넌트가 불필요해져서 사라질 때 나타나는 함수
MyComponent.js
import React, { Component } from 'react';
class MyComponent extends Component {
state = {
value: 0
};
static getDerivedStateFromProps(nextProps, prevState) { //7
if (prevState.value !== nextProps.value {
return {
value: nextProps.value //8
}
}
return null; //9
}
shouldComponentUpdate(nextProps, nextState) {
if (nextProps.value === 10) return false;
return true;
} //11
componentDidUpdate(prevProps, prevState) {
if(this.props.value !== prevProps.value) {
colsole.log('value값이 바뀌었다!');
}
}//12
componentWillUnmount() {
console.log('good bye');
} //14
render() {
return (
<div>
<p>props: {this.props.value}</p>
<p>state: {this.state.value}</p>
</div>
);
}
}
export default MyComponent;
App.js
import React, { Component } from 'react';
import MyComponent from './MyComponent';
class App extends Component {
state = {
counter: 1,
}
constructor(props){
super(props);
console.log('constructor');
}
componentDidMount() {
console.log('componentDidMount');
console.log('this.myDiv.getBoundingClientRect()');
}
handleClick = () => { //10
this.setState({
counter: this.state.counter + 1
});
}
render() {
return(
<div>
{this.state.counter < 10 && <MyComponent value={this.state.counter}/> } //13
<button onClick={this.handleClick}>Click Me</button> //10
</div>
);
}
}
counter의 값이 10보다 작을 때만 보여지게하는 코드를 넣어줘서 10을 넘어가면 사라지게 해준다. (componentWillUnmount를 실행시키기 위해)
( &&앞의 조건이 만족할 시 &&뒤를 보여지게 하는 문법임)
버튼을 10번 째 클릭해서 props와 state가 10이 될 때 props와 state는 화면에서 사라지게 되고 componentWillUnmount함수가 동작해서 콘솔창에 goodbye가 출력된다.
componentDIdCatch
만약 MyComponent.js 부분에서 에러가 난다고 하면 componentDidCatch함수는 에러가 나는 컴포넌트의 부모에서 호출해줘야한다.
MyComponent.js
import React, { Component } from 'react';
class MyComponent extends Component {
state = {
value: 0
};
static getDerivedStateFromProps(nextProps, prevState) { //7
if (prevState.value !== nextProps.value {
return {
value: nextProps.value //8
}
}
return null; //9
}
shouldComponentUpdate(nextProps, nextState) {
if (nextProps.value === 10) return false;
return true;
} //11
componentDidUpdate(prevProps, prevState) {
if(this.props.value !== prevProps.value) {
colsole.log('value값이 바뀌었다!');
}
}//12
componentWillUnmount() {
console.log('good bye');
} //14
render() {
return (
<div>
{this.props.missing.something }//15
<p>props: {this.props.value}</p>
<p>props: {this.props.value}</p>
<p>state: {this.state.value}</p>
</div>
);
}
}
export default MyComponent;
App.js
import React, { Component } from 'react';
import MyComponent from './MyComponent';
class App extends Component {
state = {
counter: 1,
}
constructor(props){
super(props);
console.log('constructor');
}
componentDidMount() {
console.log('componentDidMount');
console.log('this.myDiv.getBoundingClientRect()');
}
handleClick = () => { //10
this.setState({
counter: this.state.counter + 1
});
}
componentDidCatch(error, info) { //16
console.log(error);
console.log(info);
this.setState({
error: true,
});
//API를 통해 서버로 오류 내용 날려주기
//17
}
render() {
if (this.state.error) {
<div>에러발생</div>
}
return(
<div>
{this.state.counter < 10 && <MyComponent value={this.state.counter}/> } //13
<button onClick={this.handleClick}>Click Me</button> //10
</div>
);
}
}
error는 어떤 에러가 발생했는지를 알 수 있고 info는 어디에서 에러가 발생했는지 알려준다.
api를 사용하면 에러 발생 시 오류가 발생했다고 메시지를 띄워준 뒤 서버로 에러의 종류를 보내줄 수 있다.