2021.07.19 React Life Cycle_정리노트
오늘도 역시 7장 정리!
오늘은 라이프사이클 ( 수명주기 ) 정리..! 렌더링 되는 시점을 제어하는거구.. 어렵지만 책따라서 차근차근 해볼 예정
모든 리액트 컴포넌트에는 라이프사이클이 존재.
컴포넌트의 수명은 페이지에 렌더링 되기 전인 준비 과정에서 시작하여 페이지에서 사라질 때 끝남.
그렇기에 프로젝트를 하다보면, 가끔 컴포넌트를 처음으로 렌더링할 때 어떤 작업을 처리하거나, 컴포넌트를 업데이트 하기 전 후로 어떤 작업을 처리해야할 수도 있다. 또, 불필요한 업데이트를 방지해야할 때가 오는데, 이 때 라이프사이클 메소드를 통해 처리한다.
함수형은 새로 생긴 Hooks 에서 처리하기 때문에 오늘은 전반적인 흐름을 클래스형 컴포넌트를 이용해서 정리해볼 예정!
라이프 사이클 메서드는 총 9가지이며, 접두사에 의해서 뜻을 구분한다.
어떤 작업을 작동하기 전 메서드 Will
어떤 작업을 작동한 후의 메서드 DId
또, 3가지의 카테고리로 나뉘는데 마운트, 업데이트, 언마운트 로 나뉜다.
마운트
DOM이 생성되고, 웹 브라우저상에 나타나는 것을 뜻함.
업데이트
컴포넌트는 총 네 가지의 경우에 업데이트 되는데,
props 의 값이 바뀔 때
setState로 state 가 업데이트 될 때
부모 컴포넌트가 리렌더링 될 때 ( 자식 컴포넌트에 할당된 props 가 바뀌지 않아도, state 가 바뀌지 않아도 부모가 바뀌면 해당 )
this.forceUpdate 로 강제로 렌더링을 트리거 할 때
언마운트
마운트의 반대 과정. 컴포넌트를 DOM 에서 제가하는 것을 뜻함.
이에 따른 과정과, 메소드들이 있지만 복잡하다 보니 나는 직접 치면서 정리할 예정!
그 중에서 필수 메서드인 render() 메서드만 정리하고 나머지는 코드 치면서 정리!
render()
이 메서드는 컴포넌트 모양새(UI)를 정의. 컴포넌트에서 가장 중요한 메서드이자 라이프사이클 메서드 중 유일한 필수 메서드.
이 메서드 안에서 this.props 와 this.state 에 접근할 수 있으며, 리액트 요소 (div 와 같은 태그나 따로 선언한 컴포넌트 등등.. 아무것도 반환하고 싶지 않을 때는 null이나 false을 반환할 수 있도록 함. )를 반환한다.
주의 사항은 이벤트 설정이 아닌 곳에서 setState를 사용하면 안되며, 브라우저의 DOM 에 접근해서도 안된다.
DOM 의 정보를 가져오거나 state 에 변화를 줄 때는, componentDidMount 메소드에서 처리할 수 있다.
src/LifeCycleSample.js ( 새로 생성 )
import React, { Component } from "react";
class LifeCycleSample extends Component {
state = {
number: 0,
color: null,
};
myRef = null; //ref 설정할 부분
constructor(props) {
super(props);
console.log("constructor");
}
// props 로 받아온 값을 state에 동기화 시키는 용도로 사용. 컴포넌트가 마운트 될 때와 업데이트 될 때 호출됨.
static getDerivedStateFromProps(nextProps, prevState) {
console.log('getDerivedStateFromProps');
if (nextProps.color !== prevState.color) {
return { color: nextProps.color };
}
return null;
}
// 컴포넌트를 만들고, 첫 렌더링을 다 마친 후 실행 된다.
// 다른 자바스크립트 라이브러리 또는 프레임워크의 함수 호출, 이벤트 등록, setTimeout,setInterval ,네트워크 요청 등의 비동기 작업을 처리
componentDidMount() {
console.log("componentDidMount");
}
// props 또는 state를 변경했을 때, 리렌더링을 시작할지 여부를 지정하는 메소드.
// 반드시 true or false 반환해야하며, default 는 true.
// 이 메서드 안에서 현재 props,state 는 this를 붙여 접근하고, 샐로 설정될 props,state 는 앞에 next 를 붙여 접근 가능.
shouldComponentUpdate(nextProps, nextState) {
console.log("shouldComponentUpdate", nextProps, nextState);
return nextState.number % 10 !== 4; // 숫자 마지막 자리가 4면, 리렌더링 하지 마세여
}
// 컴포넌트를 DOM 에서 제거할 때 실행.componentDidMount에서 등록한 이벤트, 타이머, 직접 생성한 DOM 이 있다면, 여기서 제거함.
componentWillUnmount() {
console.log("componentWillUnmount");
}
handleClick = () => {
this.setState({
number: this.state.number + 1,
});
};
// render 에서 만들어진 결과물이 브라우저에 실제로 반영되기 직전에 호출.
// 이 메서드에서 반환하는 값은 componentDidUpdate 에서 세 번째 파라미터인 snapshot 값으로 전달받을 수 있다.
// 주롤 스크롤바 위치와 같이 업데이트하기 직전의 값을 참고할 일이 있을 때 활용.
getSnapshotBeforeUpdate(prevProps, proevState) {
console.log("getSnapshotBeforeUpdate");
if (prevProps.color !== this.props.color) {
return this.myRef.style.color;
}
return null;
}
// 리렌더링 완료 후 실행.
// 업데이트 끝난 직후이기 때문에 DOM 관련 처리를 해도 무방. prevProps or prevState를 통해 컴포넌트가 이전에 가졌던 데이터에 접근 가능.
// getSnapshotBeforeUpdate 에서 반환한 값이 있으면, 여기서 snapshot 값을 전달받을 수 있음.
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;
Wow.. 하나하나 주석을 달았는데 연결연결 되는 부분이 많군... 잘 다루려면 많이 쳐봐야할 것 같다.
쨋든 이 컴포넌트는 각 라이프 사이클 메서드를 실행할 때마다 콘솔 디버거에 기록하고, 부모 컴포넌트에서 props 로 색상을 받아 버튼을 누르면 state.number 값을 1씩 더한다.
getDerivedStateFromProps 에서는 부모에게서 받은 color 값을 state 에 동기화하고, getSnapshotBeforeUpdate 는 DOM 에서 변화가 일어나기 직전의 색상 속성을 snapshot 값을로 반환하여, componentDidUpdate 에서 조회할 수 있게 했다.
추가로 shouldComponenetUpdate 에서 state.number 값의 마지막 자리 수가 4이면, 리렌더링을 취소하도록 설정함!
으으... ㅠㅠ 복잡하다 복잡해 이제 App 으로 가서 props 랑 이것저것 설정해주러 갑씨다!
src/App
import React, { Component } from "react";
import LifeCycleSample from "./LifeCycleSample";
// 랜덤으로 hex 색상 코드 생성해주는 함수.
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>
{/* 버튼 렌더링하고, 누를 때마다 handleCick 메서드 호출되도록 이벤트를 설정. */}
<button onClick={this.handleClick}>랜덤색상</button>
{/* color 를 props 로 설정 */}
<LifeCycleSample color={this.state.color} />
</div>
);
}
}
export default App;
getRandomColor 함수는 state 의 color 값을 랜덤 색상으로 설정. 16777215 를 hex로 변환하면, #ffffff ( 흰색 ) 이 되어 000000 ( 검정 ) 부터 ffffff ( 흰색 ) 까지 랜덤으로 반환.
버튼을 렌더링하고 누를 때마다 handleClick 이 되도록 이벤트를 설정하고, 마지막으로 color props 를 설정해주면 끝!
자 이제 콘솔 실행화면 보기!
첫 렌더링이 끝나면, 생성자 메서드인 constructor 와 render, componnentDidMount 가 실행된다.
랜덤 색상 버튼을 누르면, 컴포넌트가 업데이트 되면서, shouldComponentUpdate 와 업데이트하기 직전의 값을 참고할 일이 있을 때 호출되는 getSnapshotBeforeUpdate 메서드가 호출된다.
더하기 버튼을 누르면, props 값이 state로 동기화 되면서 , getDerivedStateFromProps 메소드가 호출되고, 끝자리가 4가 아닌 경우, shouldComponentUpdate 메소드가 호출된다. 끝자리가 4면, 업데이트를 취소한다.
중간중간 2번씩 렌더링 되는 이유는 React.StrictMode 가 적용되어 있기 때문! index.js 에서 제거하면 한번씩 작동한다! 개발 환경에서만 두 번 호출되니까 잘못렌더링 되는 것은 아님!
흐억... 겁나 복잡하균.. 나도 정리해놓고 다음에 또 봐야할 용도로 작성했음 ㅎㅅㅎ
이제 에러를 띄워서 처리 하는 과정 정리해봅시다!!!!
src/LifeCycleSample
render 함수에서는 에러는 주로 존재하지 않는 함수를 사용하려고 하거나 , 존재하지 않는 객체의 값을 조회하려고 할 때 발생한다. 의도적으로 존재하지 않는 props 인 missing 객체의 value 를 조회해서 렌더링 해줘보자.
에러가 잘 뜨는군. 근데 이건 개발 서버라서 그렇지 만약 사용자의 입장에서 에러가 뜬다면 저 x 표시를 누르면,
이렇게 빈 화면만 뜰 거임. 이럴 때는 에러가 발생했어요 라고 따로 처리를 해주어야 하겠지!!
src/ErrorBoundary.js ( 새로 생성 )
import React, { 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;
에러가 발생하면, componentDidCatch 메서드가 호출되어, this.state.error 값을 true 로 업데이트 한다. 그러고 childeren 값을 보여주게 했다. 그러면 App 으로 가자!!
src/App
이렇게 감싸주고 다시 실행화면!
이렇게 다급한 에러 메세지가 뜨면 성공!!!!
와이구야..... 정말 생각보다 복잡한 개념.... 나도 정리해놓고 자주 볼 생각으로 정리해서 한번에 역시 이해...는 다 못한 것 같다.
일단 메소드 이름이 직관적이긴 한데 여러개 쓰니까 너무 헷갈리는 듯 ㅎㅅㅎ ...!
그래도 오늘의 포스팅은 흐름 정리라 생각하고 다음에 또 수정할거 있으면 해야징.. 끝끄으ㅡㅡ끝!
'React' 카테고리의 다른 글
2021.07.24 React styling (2) | 2021.07.24 |
---|---|
2021.07.23 React Hooks (0) | 2021.07.23 |
2021.07.19 React Component 반복 (1) | 2021.07.19 |
2021.07.16 React ref (0) | 2021.07.16 |
07.13 React event handling (0) | 2021.07.14 |
댓글