7장 컴포넌트의 라이프사이클 메서드
모든 컴포넌트에는 라이프사이클(수명 주기)가 존재함. 페이지에 렌더링되기 전인 준비과정에서 시작해서 페이지에서 사라질 때 끝난다.
이 라이프사이클 과정에서 어떤 작업을 수행할 지 메서드화 한다.
라이프사이클 메서드는 클래스형 컴포넌트에서만 사용할 수 있다.
라이프사이클 메서드의 이해
라이프사이클 메서드의 종류는 9가지이다.
- Will 붙은 메서드는 어떤 작업 작동 전에 실행되는 메서드
- Did 붙은 메서드는 어떤 작업 작동 후에 실행되는 메서드
이 메서드들을 컴포넌트 클래스에 덮어 써 선언함으로써 사용할 수 있다.
라이프사이클은마운트
,업데이트
,언마운트
세가지 카테고리로 나뉜다.
마운트
DOM이 생성되고 웹 브라우저 상에 나타나는 것을 마운트라고 한다. 이떄, 호출하는 메서드는 다음과 같다.
- constructor : 컴포넌트 새로 만들 때 호출되는 생성자 메서드
- getDerivedStateFromProps : props에 있는 값을 state에 넣을 때 사용하는 메서드
- render : 렌더링하는 메서드
- componentDidMount : 컴포넌트가 웹 브라우저상에 나타난 후 호출하는 메서드
업데이트
컴포넌트가 업데이트되는 4가지 경우
- props가 바뀔 때
- state가 바뀔 때
- 부모 컴포넌트가 리렌더링될 때
- this.forceUpdate로 강제로 렌더링 트리거 될 때
- getDerivedStateFromProps : 업데이트 시작하기 전에 호출. props변화에 따라 state값에도 변화를 주고 싶을 때 사용.
- shouldComponentUpdate : 컴포넌트가 리렌더링 해야할지 말아야할지 결정하는 메서드. true or false 반환
- render : 컴포넌트 리렌더링
- getSnapshoutBeforeUpdate : 컴포넌트 변화를 DOM에 반영하기 바로 직전에 호출하는 메서드
- componentDidUpdate : 컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드
언마운트
컴포넌트를 DOM 에서 제거하는 것을 언마운트라고 한다.
- componentWillUnmout : 컴포넌트가 웹 브라우저 상에서 사라지기 전에 호출하는 메서드
라이프사이클 메서드
render() 함수
- 컴포넌트 모양새를 정의
- 라이프사이클 메서드 중 유일한 필수 메서드
- this.props와 this.state에 접근할 수 있다.
- 이벤트 설정이 아닌 곳에서 setState를 사용하면 안되며, 브라우저의 DOM에 접근해서도 안된다.
→ DOM 정보 가져오거나 state에 변활 줄 때는componentDidMount
에서 처리해야한다.
constructor 메서드
그냥 생성자 메서드. 컴포넌트 만들 때 실행되겠지 뭐.
constructor 안에서 state 정의 보통
getDerivedStateFromProps 메서드
- props로 받아 온 값을 state에 동기화 시키는 용도로 사용
- 컴포넌트의 마운트, 업데이트 시 호출
static getDerivedStateFromProps(nextProps, prevState) {
if(nextProps.value != = prevState.value) { // 조건에 따라 특정 값 동기화
return { value: nextProps.value };
}
return null; // state를 변경할 필요가 없다면 null을 반환
}
componentDidMount 메서드
componentDidMount() { ... }
- 첫 렌더링 마친 후 실행.
- 이 안에서 다른 JS 라이브러리 or 프레임워크 함수 호출하면 된다. 이벤트 등록, setTimeout, setInterval 등등의 비동기 작업도.
shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState) { ... }
- 강제 업데이트를 제외한 업데이트 조건 충족 시 리렌더링을 할지 말지 결정하는 메서드.
- true false를 반환한다. 생성하지 않으면 default는 true
- 메서드 내부에서 현재 props와 state는 this.props 와 this.state로 접근하고 새로 설정될 props 와 satet는 nextProps 와 nextState로 접근한다.
getSanpshotBeforeUpdate 메서드
- render에서 만들어진 결과물이 브라우저에 반영되기 직전에 호출
- return 값은 componentDidUpdate에서 세번째 피라미터 값인 snapshot 값으로 받을 수 있다.
→ 주로 업데이트하기 직전의 값을 참고할 일 있을 때 활용
getSnapshotBeforeUpdate(prevProps, prevState) {
if(prevState.array != = this.state.array) {
const { scrollTop, scrollHeight } = this.list
return { scrollTop, scrollHeight };
}
}
componentDidUpdate 메서드
componentDidUpdate(prevProps, prevState, snapshot) { ... }
- 리렌더링이 완료된 후 실행.
- DOM 관련 처리해도 된다.
- prevProps, prevState 사용해서 컴포넌트가 이전에 가졌던 데이터에 접근할 수 있음.
- getSnapshotBeforeUpdate에서 반환한 값이 있으면 여기서 snapshot 값을 전달 받을 수 있다.
componentWilllUnmount 메서드
- DOM 제거할 때 실행
- componentDidMount 에서 등록한 이벤트, 타이머, 직접 생성한 DOM 제거 작업해야함.?
❓ 제거작업해야한다는데, 필수라는 말이겠지? 아직 잘모르겟음.
componentDidCatch 메서드
- 렌더링 도중에 에러가 발생했을 때 먹통이 되지않고 오류UI를 보여줄 수 있게 해준다.
- error 파라미터는 에러의 종류, infor 파라미터는 어디에 있는 코드인지 정보를 준다.
- 컴포넌트 자신에게 발생하는 에러는 못 잡고, this.props,children으로 전달되는 컴포넌트에서 밠행하는 에러만 잡을 수 있다.
componentDidCatch(error, info) {
this.setState({
error: true
});
console.log({ error, info });
}
예제
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>
);
}
}
class LifeCycleSample extends Component {
state = {
number: 0,
color: null,
};
myRef = null;
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", nextProps, nextState);
return nextProps.number % 10 != 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);
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>
);
}
}
-
constructor 보니까 super(props) 가 있음. 이를 통해 2가지를 알 수 있음
- 클래스 인스턴스를 props를 전달하면서 생성하는 구나
- constructor 명시하려면 super(props) 해줘야하 한다.
-
getDerivedStateFromProps 의 return 값이 state에 반영된다
→ 즉, setState(return 값) 해주는 느낌. -
❓ 왜 getDerivedStateFromProps 메서드를 static으로 선언할까?
⇒ https://stackoverflow.com/questions/52886075/why-is-getderivedstatefromprops-is-a-static-method
에러잡기
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;
}
}
- props.children의 값으로 컴포넌트도 사용할 수 있구나. 왜 생각을 못했지.