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
가 의존하고 있는 배열인데, 배열 안에 있는 변수들 중에 하나라도 값이 변경되었을 때 이펙트 함수가 실행됩니다. 기본적으로 이펙트 함수는 처음 컴포넌트가 렌더링 된 이후와 업데이트로 인한 재렌더링 이후에 실행됩니다. 만약 이펙트 함수가 마운트와 언마운트시에 단 한 번씩만 실행되게 하고 싶으면, 의존성 배열에 빈 배열([]
)을 넣으면 됩니다. 이렇게 하면 해당 이펙트가 props
나 state
에 있는 어떤 값에도 의존하지 않는 것이 되므로, 여러번 실행되지 않습니다. 그리고 의존성 배열은 생략할 수도 있는데, 생략하면 컴포넌트가 업데이트 될 때마다 호출됩니다. 아래 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를 사용해서 document
의 title
을 업데이트 합니다. document
의 title
은 우리가 브라우저에서 페이지를 열었을 때 창에 표시되는 문자열입니다. 크롬 브라우저의 경우 탭에 나오는 제목이라고 보면 됩니다.
위 코드처럼 의존성 배열 없이 useEffect()
를 사용하면 리액트는 "DOM이 변경된 이후에 해당 effect 함수를 실행하라." 는 의미로 받아들이게 됩니다. 그래서 기본적으로 컴포넌트가 처음 렌더링 될때를 포함해서 매번 렌더링 될 때마다 effect
가 실행된다고 보면 됩니다. 위 코드의 경우 effect function
이 처음 컴포넌트가 mount됐을 때 실행되고, 이후 컴포넌트가 업데이트 될 때마다 실행됩니다. 그래서 결과적으로는 componentDidMount()
, componentDidUpdate()
와 동일한 역할을 하게 되는 것이죠. 또한 effect
는 함수 컴포넌트 안에서 선언되기 때문에 해당 컴포넌트의 props
와 state
에 접근할 수도 있습니다. 위 코드에서는 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