모든 리액트 컴포넌트에는 생명 주기가 존재한다.
컴포넌트가 렌더링됐을 때 특정 작업을 처리하고 싶거나
업데이트 전후로 해야될 작업이 있을 수도 있고
언마운트될 때도 해야될 작업이 있을 수도 있다.
이럴 때 컴포넌트의 생명 주기 활용하면 원하는 작업을 할 수 있다.
생명 주기 내에서는 여러 메서드가 호출되며 이를 사용할 수 있는데
클래스형 컴포넌트에서는 생명 주기 메서드들을 사용하고
함수형 컴포넌트에서는 hook 중에 하나인 useEffect()를 사용하는 점에서 차이가 있다.
현재는 함수형 컴포넌트를 사용하도록 권장하고 있기 때문에
클래스형 컴포넌트에서 쓰이는 생명 주기 메서드는 사용할 일이 없다.
생명 주기는 크게 세 가지, 마운트 업데이트 언마운트로 나눌 수 있다.
컴포넌트 생명 주기
| 분류 | 클래스 컴포넌트 | 함수 컴포넌트 |
|---|---|---|
| 마운트 | constructor() | 컴포넌트 내부 |
| 마운트 | render() | return() |
| 마운트 | componentDidMount() | useEffect() |
| 업데이트 | componentDidUpdate() | useEffect() |
| 언마운트 | componentWillUnmount() | useEffect() |
컴포넌트가 생성되는 걸 마운트라고 한다.
1. constructor()를 호출한다.
constructor()에서는 state를 초기화하는 등의 작업이 실행된다.
2. render()를 호출한다.
render()에서는 화면에 표시되어야 될 내용(jsx)을 이해하고 DOM을 업데이트한다.
3. jsx가 DOM에 그려지면 componentDidmount()를 호출한다.
이 메서드는 마운트가 완료됐을 때 수행될 작업이 실행된다.
(API 호출, DOM 속성 변경 등)
컴포넌트가 변경되는 걸 업데이트라고 한다.
상태 변화를 감지하면 getDerivedStateFromProps()가 실행되고,
그 다음 화면에 표시될 내용을 다시 알아내기 위해 render() 실행된다.
그후, componentDidUpdate()가 실행된다.
getDerivedStateFromProps()는 16.3 버전 이후에 추가된 메서드이다.
props로 받아온 값을 state에 동기화시키는 용도로 사용된다.
컴포넌트가 업데이트되는 경우는 네 가지가 있다.
1. 부모로부터 전달받은 props가 변경되거나.
2. state가 변경되거나.
3. 부모 컴포넌트가 리렌더링될 때.
4. forceUpdate()로 강제로 렌더링을 트리거할 때.
forceUpdate()는 클래스 컴포넌트에서만 사용 가능한 함수이다.
componentWillUnmount()가 실행되며, 컴포넌트가 화면에서 사라지는 것을 언마운트라고 한다.
이것을 활용해서 API 연결을 해제하거나, setInterval로 함수를 반복 호출을 시켰다면, clearInterval 함수로 중단시키는 작업을 주로 처리한다.
클래스 컴포넌트의 생명 주기 메서드에서 에러가 발생했을 경우 실행되는 메서드이다.
함수 컴포넌트는 클래스 컴포넌트 생명 주기 메서드를 사용할 수 없어서
함수 컴포넌트에서 렌더링 중 에러 처리를 하고 싶다면
이 메서드를 활용한 컴포넌트를 만들고 감싸주어야 한다.
// ErrorBoundary.tsx
import { Component, ErrorInfo } from "react";
import ErrorComponent from "./ErrorComponent";
interface Props {
children: React.ReactNode;
}
interface States {
hasError: boolean;
error: Error | null;
}
class ErrorBoundary extends Component<Props, States> {
state: States = {
hasError: false,
error: null,
}
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
this.setState({
hasError: true,
error: error,
});
console.error({error, errorInfo});
}
render() {
if (this.state.hasError) {
return <ErrorComponent error={this.state.error}/>;
}
return this.props.children;
}
}
// App.tsx
// ...
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
// ...