[React] 리액트의 생명주기 메서드와 Hook
리액트 컴포넌트는 기본적으로 브라우저 상에서 나타되고, 업데이트되며, 사라지는 과정을 거치게 됩니다. 이러한 과정을 생명주기라 하며, 리액트의 모든 컴포넌트에는 생명주기가 존재합니다.
생명주기 내에서는 여러 메서드가 호출되며 이를 사용할 수 있는데 클래스형 컴포넌트에서는 생명주기 메서드를 사용하고, 함수형 컴포넌트에서는 Hook을 사용할 수 있는 점에서 서로 차이가 있습니다.
우선 리액트의 클래스형 컴포넌트의 생명주기 메서드를 알아본 다음, 함수형 컴포넌트의 Hook중 하나인 useEffect 함수를 통해 차이점을 더 자세히 알아보겠습니다.
메서드란?
: 클래스 내부에서 정의한 함수를 메서드라 부릅니다.
생명주기 메서드
클래스형 컴포넌트를 작성할 때는 아래와 같이 render() 메서드를 호출하고 JSX를 return하도록 작성해야 합니다.
import React, { Component } from 'react';
class Example extends Component {
state = {
number: 0
};
render() {
const { number } = this.state;
return (
<div>
<span>example</span>
</div>
);
}
}
export default Example;
이렇게 작성한 컴포넌트 안에는 아래 그림과 같이 constructer(), componentDidMount(), componentDidUpdate() 와 같은 다양한 생명주기 메서드들이 존재합니다. 이제 생성과 업데이트, 제거되는 과정에 대해 각각 설명하겠습니다.
Mounting
처음 컴포넌트가 생성되는 것을 마운팅(mounting)이라 합니다. 컴포넌트가 마운팅이 시작되면 아래와 같은 과정을 거칩니다.
- 컴포넌트가 처음 마운팅 될 때 React는 컴포넌트의 constructor를 호출합니다. constructor에서는 state를 초기화하는 등의 작업을 할 수 있습니다.
- 다음으로 React는 컴포넌트의 render() 메서드를 호출합니다. render() 메서드를 통해 React는 화면에 표시되어야 할 내용(JSX)을 알게 되며, DOM을 업데이트합니다.
- 마지막으로 컴포넌트의 출력값(JSX)이 DOM에 삽입되면, React는 componentDidMount() 생명주기 메서드를 호출합니다. componentDidMount() 메서드를 이용하면 컴포넌트가 마운팅 완료 되었을 때 수행할 작업, 예를들어 API를 호출하거나 DOM의 속성을 변경하는 등의 작업을 진행할 수 있습니다.
추가적으로 constructor와 render 메서드의 호출 사이에 getDerivedStateFromProps() 메서드도 호출 가능한데, 받아온 props를 state에 넣어주고 싶을 때 사용할 수 있다 는 정도로만 간단히 설명하고 넘어가겠습니다.
Updating
새로운 props를 받거나, setState()메서드로 state가 업데이트되는 등의 상황에서 리액트 컴포넌트는 업데이트됩니다.
- setState 등으로 state가 변경된 상황을 React가 인지하면 화면에 표시될 내용을 알아내기 위해 render() 메서드를 다시 호출합니다.
- render() 메서드가 호출되면 마운팅 될 때와 마찬가지로 DOM을 업데이트 하고, componentDidUpdate()메서드를 호출합니다. 이를 이용해 컴포넌트가 업데이트 되었을때의 작업을 지정할 수 있습니다.
Unmounting
리액트 컴포넌트가 삭제되는 것, 즉 화면에서 사라지는 것을 Unmount라 합니다. componentWillUnmount() 메서드는 컴포넌트가 화면에서 사라지기 직전에 호출됩니다. 이 메서드를 이용하여 API 연결을 해제하거나, 이전에 setInterval 함수를 이용하여 함수를 반복 호출했다면 clearInterval함수로 중단하는 등의 작업을 할 수 있습니다.
useEffect Hook
클래스형 컴포넌트에서 사용하는 생명주기 메서드에 대하여 알아보았으니 이번에는 함수형 컴포넌트에서 사용하는 hook중 하나인 useEffect를 생명주기 메서드와 비교해보도록 하겠습니다.
useEffect를 사용할 때 아래와 같이 첫번째 파라미터에는 함수, 두번째 파라미터에는 의존값의 배열(deps)을 넣습니다. 함수를 작성할 때 반환(return)할 수 있다는 점도 기억해 주세요.
useEffect(() => {
...
return () => {
...
}
}, [...])
useEffect는 componentDidMount, componentDidUpdate, componentWillUnmount의 역할을 수행하며 기본적으로 처음 마운트 될 때 호출됩니다. 이는 useEffect가 componentDidMount() 메서드의 역할을 기본적으로 수행한다 할 수 있습니다.
deps 배열이 존재하지 않을 때
useEffect(() => {
...
})
useEffect 내부에 함수만 작성되었고 deps 배열이 없다면 컴포넌트가 리렌더링 될 때마다 항상 호출됩니다.
이 경우에는 생명주기 메서드의 componentDidMount, componetDidUpdate 메서드와 같은 역할을 수행합니다.
deps 배열이 빈 배열일 때
useEffect(() => {
...
}, [])
deps 배열이 빈 배열일 경우에는 처음 컴포넌트가 마운트 될 때만 실행되며, componentDidMount 메서드와 같은 역할을 합니다.
deps 배열이 존재할 때
useEffect(() => {
...
}, [state, props, ...])
deps 배열이 존재할 때, 즉 배열에 state나 prop이 들어있을 때에는 이 값들이 변경될 때만 useEffect가 실행됩니다. 이는 componentDidUpdate, getDerivedStateFromProps 메서드와 같은 역할을 합니다.
함수를 반환할 때 (return)
useEffect(() => {
...
return () => {
...
}
}, [...])
첫번째 인자의 함수를 반환(return)할 수 있는데, 이때 반환하는 함수를 clean-up 함수라 표현합니다. 이 clean-up 함수가 바로 componentWillUnmount의 역할을 수행합니다.
+) useEffect를 렌더링 이전에 실행하려면
추가적으로, useEffect는 실행이 마운트가 끝났을 때, 즉 브라우저 렌더링이 완료되었을 때 실행 된다는 것에 유의해야합니다. 만약 렌더링이 완료되기 이전에, 즉 브라우저가 화면에 DOM을 그리기 전에 호출되어야 하면 useLayoutEffect() Hook을 사용할 수 있습니다.
useLayoutEffect()는 useEffect와 사용방법은 동일하며, 실행 순서에만 차이가 있습니다.