언제, 어떻게 사용해야 하는지는 알겠는데, 왜 사용해야 하는지 와닿지 않아서 정리하면서 개념을 이해해보기로 했다. 이유를 알아내려고 삽질한 과정의 기록이다...💦
📌 우선!
const [state, setState] = useState(initailValue);
여기에서 state
와 setState
는 const
이다. 변하지 않는 상수.
state
가 변경될 때, 재렌더링이 되며 각 렌더링 마다 그 동안의(또 렌더링 되기 전까지) props
와 state
는 변하지 않는다. 이 개념을 알고 있으면 좋다.
lifecycle은 react에서 클래스형 컴포넌트를 사용할 때 사용되는 개념이다. 우선 당장은 클래스형 컴포넌트를 학습하지 않을 예정이므로 Hook의 탄생 배경을 이해할 수 있을 정도로만 가볍게 이해하고 넘어가려고 한다.
함수 내의 어떤 구현이 함수 외부에 영향을 끼치는 경우
컴포넌트가 산출하고자 하는 것은 렌더링을 하는 것이다. 이 외에 DOM을 건드린다던가, 데이터를 가져온다던가, 다른 컴포넌트에 영향을 준다던가 하는 것들은 side effect이다. 렌더링을 하는 과정에서 side effect는 방해가 된다. react에서는 side effect를 따로 분리하여 관리하는 useEffect
를 사용한다.
오직 함수의 입력만이 함수의 결과에 영향을 주는 함수. 즉, side effect가 없는 함수
순수함수는 입력으로 전달된 값을 수정하지 않는다. (useState
에서 const
가 사용되는 이유일까?)
또한 순수함수는 어떤 전달 인자가 주어진 경우 항상 똑같은 값이 리턴됨을 보장하기 때문에 예측이 가능한 함수이기도 하다.
함수 컴포넌트는 props가 입력으로, JSX Element가 출력으로 나가는 순수 함수이다. 어떠한 side effect도 없어야 한다.
react에서는 다음과 같은 경우를 side effect로 여길 수 있다.
useEffect
는 클래스형 컴포넌트 lifecycle 메소드 중 componentDidMount
, componentDidUpdate
와 상응하는 함수이다. 따라서 componentDidMount
와 componentDidUpdate
의 역할에 대해서 알면 useEffect
에 대해서도 이해할 수 있을 것이다.
react 공식문서에서 안내하는 componentDidMout
와 componentDidUpdate
, 그리고 render()
의 역할에 대해 개념적으로 이해해보자.
render()
render()
함수는 순수해야 합니다. 즉, 컴포넌트의 state를 변경하지 않고 호출될 때마다 동일한 결과를 반환해야 하며 브라우저와 직접적으로 상호작용을 하지 않습니다.
브라우저와 상호작용하는 작업이 필요하다면, 해당 작업을 componentDidMount()
이나 다른 생명주기 메서드 내에서 수행하세요. render()
를 순수하게 유지해야 컴포넌트의 동작을 이해하기 쉽습니다.
render()
가 순수해야 하는 이유는 render()
의 핵심 역할 때문이다.
이전 렌더링 결과와 이번 렌더링 결과를 비교하여 바뀐 부분만 업데이트하여 화면에 그리는 것
side effect를 수행하는 것이 render phrase에 포함된다면 render()
가 핵심 역할을 수행하는 데 방해가 될 수 있다. 따라서 react는 render()
내부의 순수한 부분만을 이용해 화면을 그리고 난 뒤 useEffect
를 통해 side effect를 발생시킨다.
componentDidMount()
componentDidMount()
는 컴포넌트가 마운트된 직후, 즉 트리에 삽입된 직후에 호출됩니다. DOM 노드가 있어야 하는 초기화 작업은 이 메서드에서 이루어지면 됩니다. 외부에서 데이터를 불러와야 한다면, 네트워크 요청을 보내기 적절한 위치입니다.componentDidUpdate(prevProps, prevState, snapshot)
componentDidUpdate()
는 갱신이 일어난 직후에 호출됩니다. 이 메서드는 최초 렌더링에서는 호출되지 않습니다. 컴포넌트가 갱신되었을 때 DOM을 조작하기 위하여 이 메서드를 활용하면 좋습니다. 또한, 이전과 현재의 props
를 비교하여 네트워크 요청을 보내는 작업도 이 메서드에서 이루어지면 됩니다 (가령, props
가 변하지 않았다면 네트워크 요청을 보낼 필요가 없습니다).위의 내용을 이해한다면, 자연스럽게 useEffect의 사용 이유에 대해 알 수 있을 것이다.
✔️
useEffect
함수형 컴포넌트에서 lifecycle을 다루기 위한 목적으로 클래스형 컴포넌트의componentDidMount
,componentDidUpdate
메소드 대신 쓰이는 함수이며, 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 한다.
💻 기본 형태
import { useEffect } from 'react';
useEffect(() => {
// 실행시킬 내용
}, []);
실행 조건을 제한하기 위해 두 번째 인자 의존값 배열 deps
(dependency)를 배열 형태로 받는다.
📌 useEffect는 언제 실행되는가?
컴포넌트 생성 후 첫 렌더링(마운팅), 컴포넌트에 새로운 props 전달되며 렌더링, 컴포넌트의 state가 바뀌며 렌더링 될 때 등 (매번 새롭게 렌더링될 때) 실행된다.