[React] useEffect

Lian Kim·2022년 9월 16일
0

Hook

리액트 16.8부터 추가된 Hook은 클래스 컴포넌트에서만 사용할 수 있던 state와 여러 lifecycle(생명주기) API 기능들을 연동하여 함수 컴포넌트에서도 사용할 수 있도록 해주는 함수다 (⇒ 클래스 컴포넌트에서는 동작하지 않음). Hook의 최대 장점 중 하나는 코드를 생명주기 메서드 단위가 아니라, 기능 단위로 분리할 수 있다는 것이다.

Hook을 사용할 때는 두 가지 규칙을 준수해야 한다.

- 최상위(at the top level)에서만 호출하기 (반복문, 조건문, 중첩된 함수 내에서 실행 금지)
- 리액트 함수 컴포넌트 내에서만 호출하기 (+ 커스텀 Hook 내부)

리액트의 가장 대표적인 내장 Hook으로는 useState, useEffect를 꼽을 수 있고, 이외에도 useReducer, useMemo 등의 다양한 내장 Hook이 존재하며, 원하는 기능을 넣은 커스텀 훅을 만들어 사용할 수도 있다.

이번 글에서는 useEffect에 대해 알아볼 것이다. useEffect를 알기 위해서는 Side Effect와 Lifecycle(생명주기)에 대한 이해가 우선적으로 필요하다.






Side Effect란?

Side Effect는 함수 호출 시, 함수 내부가 아닌 외부에 영향을 미치는 것을 말한다.

let num = 0;
 
function increase(){
  num++;
}
 
increase();

위 예제의 increase 함수가 하는 일은 외부 스코프에 있는 변수 num 값을 변경하는 것 뿐이다. 함수 스코프 내부의 어떤 값을 변경시키지도 않고, 반환하는 것도 없다. 이처럼 외부 상태를 변경시키는 것을 ‘Side Effect’라고 한다.

리액트에서는 컴포넌트가 화면에 렌더링된 이후에 비동기로 처리되어야 하는 부수적인 효과들을 일컫는다. 데이터 가져오기, DOM 수동으로 조작하기 같은 것들이 해당된다.


Side Effect는 두 가지로 나눌 수 있다.

  1. 정리(clean-up)가 필요한 것
  2. 정리(clean-up)가 필요하지 않은 것 (ex. 네트워크 요청, DOM 수동 조작 등)






Lifecycle

리액트는 컴포넌트 기반의 View를 중심으로 한 라이브러리이다. 그렇다 보니 각각의 컴포넌트에는 라이프사이클(수명 주기)이 존재한다. 컴포넌트의 수명은 보통 페이지에서 렌더링되기 전인 준비 과정에서 시작하여 페이지에서 사라질 때 끝난다.

라이프사이클은 위의 그림과 같이 세 가지 카테고리로 나눌 수 있다.

  1. 생성될 때 ⇒ 마운트(DOM이 생성되고 웹 브라우저 상에 나타나는 것)
  2. 업데이트할 때 ⇒ 업데이트
  3. 제거할 때 ⇒ 언마운트(DOM에서 제거되는 것)

컴포넌트를 처음 렌더링할 때, 혹은 컴포넌트를 업데이트하기 전후로 어떤 작업을 처리해야 하거나, 불필요한 업데이트를 방지해야 할 때 라이프사이클 메서드를 사용할 수 있다. 라이프사이클 메서드는 클래스 컴포넌트에서만 사용 가능하고, 함수 컴포넌트에서는 Hook을 사용해야 한다.


라이프사이클 메서드의 종류로는 총 아홉 가지가 있는데, 우선은 useEffect와 가장 관련이 깊은 componentDidMount, componentDidUpdate, componentWillUnmount에 대해 먼저 알아보았다.


componentDidMount

컴포넌트를 만들고, 첫 렌더링을 마친 후 실행된다.
이 안에서 다른 자바스크립트 라이브러리 또는 프레임워크의 함수를 호출하거나, 이벤트 등록, 타이머 함수, 네트워크 요청 같은 비동기 작업을 처리하면 된다.


componentDidUpdate

리렌더링을 완료한 후 실행된다.
업데이트가 끝난 직후이므로, DOM 관련 처리를 해도 무방하다.


componentWillUnmount

컴포넌트를 DOM에서 제거할 때 실행된다.
componentDidMount에서 등록한 이벤트가 있다면 여기서 제거 작업을 해야한다.







useEffect란?

useEffect는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Effect Hook이다. 함수 컴포넌트 내에서 Side Effects를 수행할 수 있게 해준다. useEffect는 페이지가 처음 렌더링 되고 난 후, 무조건 한 번은 실행된다. 클래스 컴포넌트의 componentDidMount, componentDidUpdate, componentWillUnmount를 하나로 통합한 API라고 볼 수 있다.

useEffect에서 사용되는 effect는 componentDidMount, componentDidUpdate와는 달리, 브라우저가 화면을 업데이트하는 것을 차단하지 않는다. (⇒ 애플리케이션의 반응성 향상)







useEffect 사용하기

useEffect도 리액트가 제공하는 기능 중 하나이므로, import로 불러와야 한다.

import React, { useEffect } from "react";
useEffect(callback[, deps])

useEffect의 첫 번째 파라미터에는 콜백함수를, 옵셔널인 두 번째 파라미터에는 의존값이 들어있는 배열(deps)을 전달한다.


1. 컴포넌트가 마운트될 때만 실행하기

useEffect(callback, [])

두 번째 파라미터에 빈 배열을 전달하면, 컴포넌트가 화면에 맨 처음 렌더링 될 때(⇒ 마운트될 때)만 콜백 함수가 실행된다. 생명주기 메서드 componentDidMount처럼 동작한다.

// Example

useEffect(() => {
  console.log("mount");
}, [])


2. 컴포넌트가 마운트될 때와 업데이트될 때 실행하기

useEffect(callback)

두 번째 파라미터에 아무것도 전달하지 않으면, 컴포넌트가 마운트될 때와 업데이트될 때 콜백 함수가 실행된다. 생명주기 메서드 componentDidMountcomponentDidUpdate를 통합한 것처럼 동작한다.

// Example

useEffect(() => {
  console.log("mount + update");
})

useEffect(callback, [...deps])

두 번째 파라미터에 검사하고자 하는 특정 값을 넣은 배열을 전달하면, 해당 값이 업데이트될 때만 콜백 함수가 실행된다. 배열 안에는 useState를 통해 관리하고 있는 상태를 넣어줘도 되고, props로 전달받은 값을 넣어줘도 된다.



3. 컴포넌트가 언마운트될 때 실행하기

useEffect(() => { return cleanupFunc }[, deps]);

컴포넌트가 언마운트 되기 직전에 특정 작업을 수행해야 한다면, useEffect 함수의 첫 번째 파라미터로 전달되는 콜백함수에서 cleanup 함수를 return 해주면 된다. 컴포넌트가 언마운트될 때 깨끗이 정리해야 하는 코드들을 넣으면 된다. cleanup 함수는 생명주기 메서드 componentDidUnmount와 같은 기능을 한다.

// Example

useEffect(() => {
  console.log("mount");
  return () => {
    console.log("unmount");
  };
}, [])

마찬가지로, deps 배열 안에 검사하고 싶은 값을 넣어주면 해당 값이 업데이트 되기 직전에도 cleanup 함수가 실행된다.







정리

Hook

Hook은 클래스 컴포넌트에서만 사용할 수 있던 state와 여러 lifecycle(생명주기) API 기능들을 연동하여 함수 컴포넌트에서도 사용할 수 있도록 해주는 함수다. Hook을 사용하면 생명주기 메서드에 따라서가 아니라, 기능에 따라서 분리할 수 있다.

useEffect

리액트 내장 Hook 중 하나인 useEffect는 리액트 컴포넌트가 렌더링 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Effect Hook이다. 클래스 컴포넌트의 componentDidMount, componentDidUpdate, componentWillUnmount를 하나로 통합한 API라고 볼 수 있다.

useEffect의 첫 번째 파라미터에는 콜백함수를, 옵셔널인 두 번째 파라미터에는 의존성 배열(deps)을 전달한다.

+
참고
useEffect가 두 번 호출되는 이유는 StrictMode 때문이다.







참고 자료
React Hook, Lifecycle methods diagram
김민준, 『리액트를 다루는 기술』, 길벗
리액트 라이프사이클의 이해

0개의 댓글