리액트의 컴포넌트는 생성부터 소멸까지 생명 주기(라이프 사이클)
를 가지고 있습니다. 개발자는 이 생명 주기 함수들을 이용해서 컴포넌트의 생성부터 사이의 원하는 시점에 동작을 삽입할 수 있습니다.
서론에서 간단히 소개했듯이 리액트의 모든 컴포넌트들은 생명 주기
를 가지고 동작합니다. 단순히 만들고 실행에서 끝나는 것이 아니라 만드는 순간부터 실행 종료 사이사이 모든 순간들을 메소드로 나누어 관리합니다. 이것들을 컴포넌트 라이프 사이클 메소드
라고 합니다. 컴포넌트 라이프 사이클 메소드
는 클래스형 컴포넌트에서만 직접 사용이 가능합니다.
함수형 컴포넌트에서는 라이프 사이클 메소드 대신 Hooks
기능을 이용해서 라이프 사이클 메소드와 비슷한 용도로 사용할 수 있습니다. 이 포스트의 현재 목적은 라이프 사이클 메소드의 이해이므로 Hooks를 이용한 함수형 컴포넌트 방식은 다음에 따로 다루고, 클래스형 컴포넌트의 라이프 사이클 메소드를 알아보겠습니다.
컴포넌트는 크게 세 가지 주기를 가집니다. 컴포넌트를 브라우저에 그리는 마운트(Mount)
, 컴포넌트를 브라우저에 그린 후 변경 사항을 그리는 업데이트(Update)
, 컴포넌트를 브라우저에서 제거하는 언마운트(Unmount)
과정을 가지고있습니다.그럼 이제 각 과정에서 사용되는 라이프 사이클 메소드들을 알아보겠습니다.
처음으로 살펴볼 라이프 사이클 메소드들은 마운트
과정에서 사용할 수 있는 라이프 사이클 메소드들 입니다. 각 라이프 사이클 메소드들은 특징을 가지고 있는데요. 게터(getter)와 세터(setter)처럼 메소드 이름에 will
이 붙으면 특정 작업 이전에 실행되는 메소드이고, did
가 붙으면 특정 작업 이후에 실행된다는 특징을 가지고 있습니다.
마운트(Mount)
란 DOM이 생성되어 브라우저에 나타나는 과정을 말합니다. 즉, 컴포넌트를 만들고 브라우저에 표시되게 하는 것 까지의 과정을 마운트
라고 할 수 있습니다.
constructor(props) {}
생성자라는 이름 답게, constructor
는 컴포넌트를 새로 생성할 때 마다 호출되는 메소드입니다. state를 다룰 때 예제에서 한 번 등장한 적이 있었습니다. constructor
는 컴포넌트 생성시 가장 처음 호출되는 동시에, state나 객체 변수 등을 선언할 때 사용됩니다.
getDerivedStateFromProps(props, state) {}
props로 전달된 인자 값을 state에 넣을 때 이용하는 메소드입니다. 이 메소드는 정적 메소드라서 this 등을 이용한 접근은 허용되지 않고 인자로 전달된 값을 통해서 사용해야합니다. 이때 props는 상위 컴포넌트에서 인수로 전달한 값이고, state는 현재 컴포넌트의 state 값입니다. 즉 이 메소드는 보통 상위에서 정보를 받아 현재 state에 적용하는 식으로 이용하게 됩니다.
render() {}
render
메소드도 클래스형 컴포넌트를 다룰때 봤던 메소드입니다. 이 메소드 역시 라이프 사이클 메소드입니다.컴포넌트를 웹 페이지에 그릴 때 호출 되는 함수입니다. render() {}
내부의 JSX를 화면에 그려줍니다.
componentDidMount() {}
컴포넌트가 브라우저에 생성되어 표시된다면 호출되는 메소드입니다. js에서 DOM을 조작할 때 DOMContentLoaded
처럼 모든 컴포넌트가 그려진 이후에 특정 동작을 실행하고 싶다면, 이 메소드를 이용하게 됩니다.
이번에는 업데이트 과정에서 사용가능한 라이프 사이클 메소드들입니다. 업데이트 과정을 거친 컴포넌트는 리렌더링을 통해서 브라우저에 나타나게 됩니다. 업데이트
는 컴포넌트에 변경사항이 발생될 때 업데이트를 실시하는데, 이는 다음 네 가지 경우에 업데이트를 실시합니다.
getDerivedStateFromProps(props, state) {}
이 메소드는 조금 전 마운트 과정에서도 있었습니다. 마찬가지로 업데이트 내역을 현재 컴포넌트에 적용하기 위해 사용합니다.
shouldComponentUpdate(nextProps, nextState) {}
이 메소드는 컴포넌트를 리렌더링을 할지 말지 결정합니다. 그래서 반환값으로 true/false를 가집니다. true를 반환할 시에는 계속해서 생명주기를 진행하고 false를 반환할 경우 중지합니다. 데이터 비교가 포함된 메소드라 성능에 영향을 주는 메소드이기도 합니다. 또한 this.forceUpdate()
통해 강제로 리렌더링 하는 경우에 이 메소드는 실행되지 않습니다.
마찬가지로 업데이트한 컴포넌트의 리렌더링을 위해 render 메소드를 포함하고 있습니다. 사용법은 위에서 다뤘으므로 생략하겠습니다.
getSnapshotBeforeUpdate(preProps, preState) {}
리렌더링 직전에 호출되는 메소드입니다. 이 메소드는 출력 직전에 호출되므로, 출력 직전의 렌더링 요소 크기나 스크롤 위치등의 DOM의 정보에 접근할 때 사용합니다.
componentDidUpdate(preProps, preState, snapshot) {}
컴포넌트가 모든 업데이트를 마친 후에 호출 됩니다. 세번째 인자인 snapshot
은 getSnapshotBeforeUpdate()
함수로 부터 반환된 DOM정보를 전달 받은 인자입니다. 이 3가지 인자들을 이용해서 스크롤 위치 변경 등의 DOM 정보 변경이 가능합니다.
언마운트
는 DOM에서 컴포넌트를 제거하는 과정입니다. 당연하지만 삭제과정은 컴포넌트를 삭제하는 것이라 삭제하기 직전에만 컴포넌트를 제어할 수 있습니다.
componentWillUnmount() {}
컴포넌트가 브라우저에서 삭제되기 직전에 호출되는 메소드입니다. 보통 컴포넌트 내에서 메모리를 잡고있는 컴포넌트 일 경우 메모리 해제를 위해 사용됩니다.
위에서 알아본 컴포넌트의 라이프 사이클을 정리하면 다음과 같이 나타낼 수 있습니다.
import React from 'react';
class ComponentLifeCycle extends React.Component {
constructor(props) {
super(props);
this.state = {
destroyed: false,
};
console.log("constructor() 메소드 호출");
}
static getDerivedStateFromProps() {
console.log("getDerivedStateFromProps() 메소드 호출");
return {};
}
componentDidMount() {
console.log("componentDidMount() 메소드 호출");
this.setState({updated: true});
}
shouldComponentUpdate() {
console.log("shouldComponentUpdate() 메소드 호출");
return true;
}
getSnapshotBeforeUpdate() {
console.log("getSnapshotBeforeUpdate() 메소드 호출");
return {};
}
componentDidUpdate() {
console.log("componentDidUpdate() 메소드 호출");
}
componentWillUnmount() {
console.log("componentWillUnmount() 메소드 호출")
}
render() {
console.log("render() 메소드 호출");
return null;
}
}
export default ComponentLifeCycle;
위에서 본 순서대로 선언 순서에 상관없이 컴포넌트 생명 주기에 따라서 호출이 되었죠? 여기서는 따로 삭제 과정을 거치지 않았기 때문에 componentWillUnMount가 실행되지 않았지만, 삭제를 준다면 제일 마지막에 componentWillUnMount가 호출될 것 입니다.