리액트의 모든 컴포넌트에는 생명주기(Life Cycle)가 존재한다.
컴포넌트의 수명은 보통 페이지에서 렌더링되기 전인 준비 과정에서 시작하여 페이지에서 사라질 때 끝이 난다.
라이프 사이클을 다룬다는 것은 컴포넌트가 생겨나고, 변화하고, 없어지는 일련의 프로세스를 프로그래머가 통제하는 것을 뜻한다.
기존에는 Class형 컴포넌트만 생명주기 처리가 가능했지만, React 16.8 부터는 Hooks가 도입되어 함수형 컴포넌트에서도 생명주기 처리가 가능해졌다.
Life Cycle은 크게 세 단계로 나누어진다.
Class 방식과 함수 방식에 따른 Life Cycle을 살펴보자.
출처: https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
클래스 방식 컴포넌트의 Life Cycle은 위와 같이 9가지로 분류된다.
위 9가지의 메서드들을 각각 알아보자.
Mounting은 컴포넌트가 DOM에 처음 추가될 때 발생한다.
실행 순서는 이러하다.
constructor() -> getDerivedStateFromProps() -> render() -> componentDidMount()
클래스 인스턴스 객체를 생성하고 초기화하는 메서드이다.
이 메서드에서 초기 state를 설정할 수 있다.
props로 받아온 값을 기반으로 state에 동기화시킨다.
Mounting 단계와 Updating 단계에서 호출된다.
정적 메서드이며, render() 메서드를 호출하기 직전에 호출된다.
가장 기초적이면서 중요한 render() 메서드
최종적으로 작업한 결과물을 return 하는 기능을 가짐
JSX를 HTML로 반환하는 필수 메서드이다!
실제 DOM에 컴포넌트가 렌더링된 후 호출됨
오직 초기 컴포넌트의 로딩 이후에 한번만 실행되는 라이프사이클 메소드
업데이트는 props나 state가 변경될 때 발생한다.
실행 순서는 이러하다.
getDerivedStateFromProps() -> shouldComponentUpdate() -> render() -> getSnapshotBeforeUpdate() -> componentDidUpdate()
업데이트 시에도 마운트 때와 마찬가지로 먼저 호출됨
이 메서드는 렌더 전에 state를 조정할 수 있는 유일한 방법이다.
props나 state를 변경했을 때, 리렌더링을 할지 말지 결정하는 메서드
기본적으로 true를 반환
조건에 따라 false를 반환하면 해당 조건에는 render 함수를 호출하지 않음
오직 성능 최적화만을 위한 메서드
JSX를 다시 HTML로 반환
render에서 만들어진 결과가 브라우저에 실제로 반영되기 직전에 호출
DOM 업데이트 전 마지막 스냅샷을 캡처 (예: 스크롤 위치)
컴포넌트의 변경이 완료되었을 때 수행되는 메소드
업데이트가 끝난 직후이므로 DOM관련 처리를 해도 무방하다.
컴포넌트가 DOM에서 제거될 때 호출된다.
타이머 해제, 구독 취소, 정리 작업 등을 수행
React 16.8부터는 Hooks가 도입되며, 함수형 컴포넌트에서도 상태 관리와 생명주기 처리가 가능해졌다.
생명주기와 관련된 주요 Hook은 useEffect!
활용 방법은 아래와 같다.
useEffect(() => {
// 마운트 & deps 변경 시 실행
return () => {
// 언마운트 또는 deps 변경 직전 실행
};
}, [dependencies]);
Class Component:
componentDidMount() {
this.subscription = props.data.subscribe(this.handleDataChange);
}
componentDidUpdate(prevProps) {
if (prevProps.data !== props.data) {
this.subscription.unsubscribe();
this.subscription = props.data.subscribe(this.handleDataChange);
}
}
componentWillUnmount() {
this.subscription.unsubscribe();
}
Function Component (useEffect
):
useEffect(() => {
const subscription = props.data.subscribe(handleDataChange);
return () => {
subscription.unsubscribe();
};
}, [props.data]);
이처럼 useEffect Hook을 활용해 코드를 더 깔끔하게 만들 수 있다.
만약 shouldComponentUpdate
를 함수형 컴포넌트에서 사용하고 싶다면?
➡️ React.memo()
를 사용하면 된다.
shouldComponentUpdate
는 props나 state를 변경했을 때, 리렌더링을 할지 말지 결정하는 메서드였다.
이와 비슷하게, React.memo()
는 현재 props를 이전 props와 비교하고,
같다면 리렌더링을 생략하는 기능을 가진다.
Class 컴포넌트보다 함수형 컴포넌트가 더 간결하고 읽기 쉬우며, 더 유연하게 상태나 사이드 이펙트 등을 관리하기 좋다고 하니, 앞으로 함수형 컴포넌트를 사용하는게 좋을 것 같다.