처음 만난 리액트 문서


7.3 useEffect()

useState()와 같이 가장 많이 사용되는 훅으로 useEffect()가 있습니다. useEffect()side effect를 수행하기 위한 훅입니다. 그렇다면 side effect가 무엇인지부터 알아야겠죠? side effect는 사전적인 의미로는 부작용이라는 뜻을 갖고 있습니다. 원래 단어의 의미 자체가 부정적인 편인데, 컴퓨터 프로그래밍에서도 부정적인 의미로 사용되기도 합니다. 코드가 실행될 때 개발자가 의도하지 않은대로 실행되면서 버그가 발생하게 되면 이를 side effect가 발생했다고 말합니다. 하지만 리액트에서의 side effect는 부정적인 의미는 아닙니다. 리액트에서 말하는 side effect는 그냥 effect라는 의미에 더 가까운데, 예를 들면 서버에서 데이터를 받아오거나, 수동으로 DOM을 변경하는 등의 작업을 의미합니다. 이런 작업들을 effect라고 부르는 이유는 이 작업들이 다른 컴포넌트들에 영향을 미칠 수 있으며, 렌더링 중에는 작업이 완료될 수 없기 때문입니다. 렌더링이 끝난 이후에 실행되어야 하는 작업들이죠.

useEffect()는 리액트의 함수 컴포넌트에서 side effect를 실행할 수 있도록 해주는 훅입니다. useEffect()는 클래스 컴포넌트에서 제공하는 라이프사이클 함수인 componentDidMount(), componentDidUpdate(), 그리고 componentWillUnmount()와 동일한 기능들을 하나로 통합해서 제공합니다. 그래서 useEffect()훅 만으로 위의 라이프사이클 함수와 동일한 기능들을 수행할 수 있습니다. useEffect()는 아래와 같이 사용합니다.

useEffect(이펙트 함수, 의존성 배열);

첫 번째 파라미터로는 이펙트 함수(effect function)가 들어가고, 두 번째 파라미터로는 의존성 배열(an array of dependencies)이 들어갑니다. 의존성 배열은 말 그대로 이 effect가 의존하고 있는 배열인데, 배열 안에 있는 변수들 중에 하나라도 값이 변경되었을 때 이펙트 함수가 실행됩니다. 기본적으로 이펙트 함수는 처음 컴포넌트가 렌더링 된 이후와 업데이트로 인한 재렌더링 이후에 실행됩니다. 만약 이펙트 함수가 마운트와 언마운트시에 단 한 번씩만 실행되게 하고 싶으면, 의존성 배열에 빈 배열([])을 넣으면 됩니다. 이렇게 하면 해당 이펙트가 propsstate에 있는 어떤 값에도 의존하지 않는 것이 되므로, 여러번 실행되지 않습니다. 그리고 의존성 배열은 생략할 수도 있는데, 생략하면 컴포넌트가 업데이트 될 때마다 호출됩니다. 아래 useEffect()를 사용한 예제 코드를 한 번 보도록 하겠습니다.

import React, { useState, useEffect } from "react";

function Counter(props) {
    const [count, setCount] = useState(0);

    // componentDidMount, componentDidUpdate와 비슷하게 작동
    useEffect(() => {
        // 브라우저 API를 사용해서 document의 title을 업데이트
        document.title = `You clicked ${count} times`;
    });

    return (
        <div>
            <p>총 {count}번 클릭했습니다.</p>
            <button onClick={() => setCount(count + 1)}>
                클릭
            </button>
        </div>
    );
}

위 코드는 앞에서 useState()를 배울 때 살펴본 코드와 거의 동일합니다. 추가로 useEffect() 훅을 사용하고 있습니다. useEffect()를 사용해서 클래스 컴포넌트에서 제공하는 componentDidMount(), componentDidUpdate() 같은 라이프사이클 함수들의 기능을 동일하게 수행하도록 만들었습니다. useEffect()안에 있는 이펙트 함수에서는 브라우저에서 제공하는 API를 사용해서 documenttitle을 업데이트 합니다. documenttitle은 우리가 브라우저에서 페이지를 열었을 때 창에 표시되는 문자열입니다. 크롬 브라우저의 경우 탭에 나오는 제목이라고 보면 됩니다.

위 코드처럼 의존성 배열 없이 useEffect()를 사용하면 리액트는 "DOM이 변경된 이후에 해당 effect 함수를 실행하라." 는 의미로 받아들이게 됩니다. 그래서 기본적으로 컴포넌트가 처음 렌더링 될때를 포함해서 매번 렌더링 될 때마다 effect가 실행된다고 보면 됩니다. 위 코드의 경우 effect function이 처음 컴포넌트가 mount됐을 때 실행되고, 이후 컴포넌트가 업데이트 될 때마다 실행됩니다. 그래서 결과적으로는 componentDidMount(), componentDidUpdate()와 동일한 역할을 하게 되는 것이죠. 또한 effect는 함수 컴포넌트 안에서 선언되기 때문에 해당 컴포넌트의 propsstate에 접근할 수도 있습니다. 위 코드에서는 count라는 state에 접근해서 해당 값이 포함된 문자열을 생성해서 사용하는 것을 볼 수 있습니다.

그렇다면 componentWillUnmount()와 동일한 기능은 useEffect()로 어떻게 구현할 수 있을까요? 아래 예제 코드를 한 번 보도록 하겠습니다.

import React, { useState, useEffect } from "react";

function UserStatus(props) {
    const [isOnline, setIsOnline] = useState(null);

    function handleStatusChange(status) {
        setIsOnline(status.isOnline);
    }

    useEffect(() => {
        ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
        return () => {
            ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
        };
    });

    if (isOnline === null) {
        return '대기중...';
    }
    return isOnline ? '온라인' : '오프라인';
}

위 코드에서는 useEffect()에서 먼저 ServerAPI를 사용해서 사용자의 상태를 구독하고 있습니다. 그리고 이후에 함수를 하나 리턴하는데, 해당 함수 안에는 구독을 해지하는 API를 호출하도록 되어 있습니다. useEffect()에서 리턴하는 함수는 컴포넌트가 마운트 해지될 때 호출됩니다. 결과적으로 useEffect()의 리턴 함수의 역할은 componentWillUnmount()함수가 하는 역할과 동일하게 됩니다.

그리고 useEffect()훅은 하나의 컴포넌트에 여러개를 사용할 수 있습니다. 아래 코드는 두 개의 useEffect()훅을 사용하는 코드입니다.

function UserStatusWithCounter(props) {
    const [count, setCount] = useState(0);
    useEffect(() => {
        document.title = `총 ${count}번 클릭했습니다.`;
    });

    const [isOnline, setIsOnline] = useState(null);
    useEffect(() => {
        ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
        return () => {
            ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
        };
    });

    function handleStatusChange(status) {
        setIsOnline(status.isOnline);
    }

    // ...

마지막으로 지금까지 배운 useEffect()훅의 사용법을 다시 자세하게 정리해보면 아래와 같습니다. useEffect()는 굉장히 자주 사용하기 때문에 꼭 이 구조를 기억해두기 바랍니다.

useEffect(() => {
    // 컴포넌트가 마운트 된 이후,
    // 의존성 배열에 있는 변수들 중 하나라도 값이 변경되었을 때 실행됨
    // 의존성 배열에 빈 배열(`[]`)을 넣으면 마운트와 언마운트시에 단 한 번씩만 실행됨
    // 의존성 배열 생략시 컴포넌트 업데이트시마다 실행됨
    ...

    return () => {
        // 컴포넌트가 마운트 해지 되기 전에 실행됨
        ...
    }
}, [의존성 변수1, 의존성 변수2, ...]);

마지막 업데이트: 2025년 08월 21일 09시 05분

이 문서의 저작권은 이인제(소플)에 있습니다. 무단 전재와 무단 복제를 금합니다.

On this page

  • 7.3 useEffect()