
React의 useEffect는 컴포넌트의 생명주기를 관리하고 side effects를 처리하는 데 필수적인 Hook입니다. 이 포스트에서는 useEffect의 기본 사용법, 동작 시점, 클린업 처리, 그리고 주의사항에 대해서 설명합니다. 이를 통해 useEffect를 이해하고 효율적으로 활용하는데 도움이 됐으면 좋겠습니다.
1. useEffect
란 무엇인가?
useEffect
는 React의 함수형 컴포넌트에서 side effects를 처리하기 위해 사용됩니다. side effects란 컴포넌트의 렌더링 외에 발생하는 작업을 의미하며, 다음과 같은 작업을 포함합니다:
- 데이터 가져오기 (API 호출)
- DOM 조작
- 타이머 설정
- 이벤트 리스너 등록 및 해제
React 컴포넌트는 기본적으로 렌더링에만 집중하도록 설계되어 있지만, 실제 애플리케이션에서는 렌더링 외에도 다양한 작업이 필요합니다. 이때, useEffect를 사용하면 이러한 작업을 컴포넌트의 생명주기에 맞춰 쉽게 처리할 수 있습니다.
2. useEffect
의 기본 사용법
useEffect
는 두 가지 주요 인자를 받습니다:
- 콜백 함수: 실행할 작업을 정의합니다.
- 의존성 배열 (Dependency Array): 어떤 값이 변경될 때만 콜백을 실행할지 결정합니다.
2.1. 의존성 배열이 없는 경우
useEffect(() => {
console.log("렌더링될 때마다 실행됩니다.");
});
- 컴포넌트가 마운트되거나 업데이트될 때마다 실행됩니다.
- 모든 렌더링마다 실행되므로, 성능에 영향을 줄 수 있습니다.
2.2. 빈 배열을 전달한 경우
useEffect(() => {
console.log("초기 렌더링 시 한 번만 실행됩니다.");
}, []);
- 컴포넌트가 처음 마운트될 때만 실행됩니다.
- 이후 업데이트 시에는 실행되지 않습니다.
2.3. 특정 값에 의존하는 경우
useEffect(() => {
console.log(`count 값이 변경됨: ${count}`);
}, [count]);
count
값이 변경될 때만 실행됩니다.- 의존성 배열에 포함된 값이 변경되지 않으면 실행되지 않습니다.
3. useEffect
의 동작 시점
React의 useEffect
는 컴포넌트의 렌더링 이후에 실행됩니다. 이는 React가 DOM 업데이트를 완료한 후에 useEffect
내부의 콜백 함수가 실행된다는 것을 의미합니다.
동작 시점
- 초기 렌더링 후 실행
- 컴포넌트가 처음 화면에 렌더링된 직후 실행됩니다.
- 의존성 배열을 빈 배열(
[]
)로 설정하면 초기 렌더링 시 한 번만 실행됩니다.
- 의존성 값 변경 시 실행
- 의존성 배열에 포함된 값이 변경될 때마다 실행됩니다.
- 컴포넌트 언마운트 시 실행 (클린업 함수)
- 컴포넌트가 화면에서 사라질 때, 또는 다음 렌더링 전에 클린업 함수가 실행됩니다.
4. 클린업(Cleanup) 처리
useEffect
는 컴포넌트가 언마운트되거나, 다음 렌더링 전에 정리 작업을 수행할 수 있도록 클린업 함수를 제공합니다. 클린업은 다음과 같은 작업에 유용합니다:
- 타이머 정리
- 이벤트 리스너 제거
- 구독 해제
클린업 함수 사용법
useEffect(() => {
const timer = setInterval(() => {
console.log("타이머 실행 중...");
}, 1000);
return () => {
clearInterval(timer); // 타이머 정리
console.log("타이머가 종료되었습니다.");
};
}, []);
return
으로 반환된 함수는 컴포넌트가 언마운트되거나, 다음 렌더링 전에 실행됩니다.- 이를 통해 메모리 누수를 방지할 수 있습니다.
5. 예제 코드
5.1. 기본 예제: 렌더링 시점 확인
import React, { useState, useEffect } from "react";
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("렌더링 완료 후 실행");
});
useEffect(() => {
console.log("초기 렌더링 시 한 번만 실행");
}, []);
useEffect(() => {
console.log(`count 값이 변경됨: ${count}`);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase Count</button>
</div>
);
}
export default Example;
5.2. 클린업 예제: 타이머 컴포넌트
import React, { useState, useEffect } from "react";
function Timer() {
useEffect(() => {
const timer = setInterval(() => {
console.log("타이머 실행 중...");
}, 1000);
return () => {
clearInterval(timer);
console.log("타이머가 종료되었습니다.");
};
}, []);
return <div>타이머가 실행 중입니다.</div>;
}
function App() {
const [showTimer, setShowTimer] = useState(false);
return (
<div>
<button onClick={() => setShowTimer(!showTimer)}>
{showTimer ? "타이머 종료" : "타이머 시작"}
</button>
{showTimer && <Timer />}
</div>
);
}
export default App;
6. useEffect
사용 시 주의 사항
- 의존성 배열 관리:
- 의존성 배열에 포함된 값이 변경될 때만
useEffect
가 실행됩니다. - 의존성 배열을 잘못 설정하면, 의도치 않은 동작이나 성능 문제가 발생할 수 있습니다.
- 의존성 배열에 포함된 값이 변경될 때만
- 무거운 작업은 피하기:
useEffect
내부에서 무거운 작업을 수행하면 렌더링 성능에 영향을 줄 수 있습니다.- 무거운 작업은 별도의 함수로 분리하거나, 비동기 작업으로 처리하세요.
- 클린업 함수 작성:
- 타이머, 이벤트 리스너, 구독 등은 반드시 클린업 함수를 통해 정리해야 합니다.
- 그렇지 않으면 메모리 누수(memory leak)가 발생할 수 있습니다.
- 비동기 작업 주의:
useEffect
내부에서 비동기 작업을 수행할 때, 비동기 함수 자체를useEffect
에 직접 전달하지 마세요.- 비동기 작업은
useEffect
내부에서 별도의 함수로 정의해야 작업의 흐름을 명확히 제어할 수 있습니다. useEffect
는 반환값으로 클린업 함수(cleanup function)를 기대하는 반면 비동기 함수는Promise
를 반환하므로, useEffect에 직접 전달하면 React가 이를 클린업 함수로 잘못 처리할 수 있습니다
7. 요약
React의 useEffect
는 컴포넌트의 생명주기를 관리하고, 부수효과를 처리하는 데 필수적인 Hook입니다. 주요 포인트는 다음과 같습니다:
- 렌더링마다 실행: 의존성 배열이 없을 때.
- 마운트 시 한 번 실행: 빈 배열을 전달할 때.
- 특정 값 변경 시 실행: 의존성 배열에 값을 전달할 때.
- 클린업 함수: 컴포넌트 언마운트 시 정리 작업을 수행.
useEffect
를 적절히 활용하면 React 애플리케이션의 상태 관리와 성능 최적화에 큰 도움을 줄 수 있습니다.
