useEffect란?
React는 UI를 구축하기 위한 라이브러리로, 컴포넌트의 상태(state)와 속성(props)에 따라 화면을 렌더링합니다. 그러나 **데이터 가져오기, 수동으로 DOM을 조작하기, 구독 설정 등과 같은 부수 효과(side effects)**를 처리해야 할 때가 있습니다. 이러한 부수 효과를 관리하기 위해 React는 함수형 컴포넌트에서 useEffect Hook을 제공합니다.
useEffect는 컴포넌트가 렌더링될 때마다 특정 작업을 수행할 수 있도록 도와줍니다. 클래스형 컴포넌트의 생명주기 메서드인 componentDidMount, componentDidUpdate, componentWillUnmount를 대체하며, 함수형 컴포넌트에서도 이러한 생명주기 메서드의 기능을 구현할 수 있게 해줍니다.
useEffect의 기본 사용법
useEffect의 기본적인 사용법은 다음과 같습니다.
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// 수행할 작업
console.log('컴포넌트가 렌더링되었습니다.');
// 정리 함수 반환 (선택 사항)
return () => {
console.log('컴포넌트가 언마운트됩니다.');
};
}, []); // 의존성 배열
return <div>안녕하세요, 리액트!</div>;
}
위 코드에서 useEffect는 첫 번째 인자로 함수를 받습니다. 이 함수는 컴포넌트가 렌더링된 후 실행되며, 선택적으로 정리(clean-up) 함수를 반환할 수 있습니다. 두 번째 인자로는 의존성 배열(dependency array)을 받는데, 이 배열에 지정된 값이 변경될 때마다 useEffect가 다시 실행됩니다. 만약 빈 배열 []을 전달하면, 컴포넌트가 처음 마운트될 때만 실행되고 이후에는 실행되지 않습니다.
useEffect의 다양한 사용 패턴
useEffect는 의존성 배열의 구성에 따라 다양한 패턴으로 사용할 수 있습니다.
1. 마운트 시 한 번만 실행
useEffect(() => {
// 컴포넌트가 마운트될 때 실행
console.log('컴포넌트가 마운트되었습니다.');
}, []);
의존성 배열이 빈 배열인 경우, 컴포넌트가 처음 마운트될 때만 실행됩니다.
2. 특정 값이 변경될 때마다 실행
useEffect(() => {
// 컴포넌트가 렌더링될 때마다 실행
console.log('컴포넌트가 렌더링되었습니다.');
});
의존성 배열에 count를 넣으면, count 값이 변경될 때마다 useEffect가 실행됩니다.
3. 모든 렌더링마다 실행
useEffect(() => {
// 컴포넌트가 렌더링될 때마다 실행
console.log('컴포넌트가 렌더링되었습니다.');
});
의존성 배열을 생략하면, 컴포넌트가 렌더링될 때마다 useEffect가 실행됩니다.
4. 정리(clean-up) 함수 사용
useEffect(() => {
const timer = setInterval(() => {
console.log('타이머 실행 중...');
}, 1000);
// 컴포넌트가 언마운트될 때 또는 의존성이 변경될 때 타이머 정리
return () => {
clearInterval(timer);
console.log('타이머가 정리되었습니다.');
};
}, []);
useEffect 내부에서 정리 함수를 반환하면, 컴포넌트가 언마운트되거나 의존성 값이 변경될 때 해당 함수가 실행되어 리소스를 정리합니다.
useEffect와 useState를 함께 사용한 실전 예제 10선
이제 useEffect와 useState를 함께 사용하여 실제로 어떻게 활용할 수 있는지 10가지 예제를 살펴보겠습니다.
1. API 데이터 가져오기
import React, { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(result => setData(result))
.catch(error => console.error('데이터 가져오기 오류:', error));
}, []);
return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
설명:
• useState를 사용하여 data라는 상태를 정의하고, 초기값을 빈 배열로 설정합니다.
• useEffect는 컴포넌트가 마운트될 때 한 번 실행되어 API로부터 데이터를 가져옵니다.
• 데이터를 성공적으로 가져오면 setData를 통해 상태를 업데이트하고, 이를 리스트 형태로 렌더링합니다.
2. 윈도우 크기 감지
import React, { useState, useEffect } from 'react';
function WindowSize() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => {
setWidth(window.innerWidth);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return <h1>현재 창 너비: {width}px</h1>;
}
설명
1) useState를 사용하여 width 상태를 정의
• const [width, setWidth] = useState(window.innerWidth);
• width는 현재 창의 너비를 저장하는 상태 변수입니다.
• window.innerWidth를 초기값으로 설정하여 컴포넌트가 처음 렌더링될 때 현재 브라우저 창의 너비를 반영합니다.
2) useEffect를 활용하여 창 크기가 변경될 때 상태 업데이트
• useEffect 내부에서 window.addEventListener('resize', handleResize);를 등록합니다.
• handleResize 함수는 창 크기가 변경될 때마다 setWidth(window.innerWidth);를 호출하여 width 값을 최신 상태로 유지합니다.
3) 컴포넌트가 언마운트될 때 window.removeEventListener로 이벤트 리스너 제거
• 리소스 낭비를 방지하기 위해 useEffect에서 이벤트 리스너를 정리하는 클린업(clean-up) 함수를 사용합니다.
• return () => { window.removeEventListener('resize', handleResize); }
• 이는 컴포넌트가 제거되거나 리렌더링될 때 불필요한 이벤트 리스너가 남아 있지 않도록 정리하는 역할을 합니다.
4) width 상태를 화면에 출력
• return <h1>현재 창 너비: {width}px</h1>;
• 실시간으로 화면의 가로 크기를 보여주는 UI를 렌더링합니다.
3. 다크 모드 구현하기
import React, { useState, useEffect } from 'react';
function DarkModeToggle() {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
document.body.style.backgroundColor = darkMode ? 'black' : 'white';
document.body.style.color = darkMode ? 'white' : 'black';
}, [darkMode]);
return (
<button onClick={() => setDarkMode(!darkMode)}>
{darkMode ? '라이트 모드' : '다크 모드'}
</button>
);
}
✅ useEffect를 이용해 darkMode 상태가 변경될 때마다 배경색과 글자색을 변경하는 예제입니다.
4. 로컬 스토리지 활용 (로그인 상태 저장)
import React, { useState, useEffect } from 'react';
function LoginStatus() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
const storedStatus = localStorage.getItem('isLoggedIn');
if (storedStatus === 'true') setIsLoggedIn(true);
}, []);
useEffect(() => {
localStorage.setItem('isLoggedIn', isLoggedIn);
}, [isLoggedIn]);
return (
<div>
<h1>{isLoggedIn ? '로그인됨' : '로그아웃됨'}</h1>
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>
{isLoggedIn ? '로그아웃' : '로그인'}
</button>
</div>
);
}
✅ 로컬 스토리지에 로그인 상태를 저장하여 페이지를 새로고침해도 상태가 유지됩니다.
5. 타이머 기능 만들기
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <h1>경과 시간: {seconds}초</h1>;
}
✅ useEffect를 이용해 타이머 기능을 구현하는 예제입니다.
6. 마우스 위치 추적하기
import React, { useState, useEffect } from 'react';
function MouseTracker() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const updatePosition = (e) => setPosition({ x: e.clientX, y: e.clientY });
window.addEventListener('mousemove', updatePosition);
return () => window.removeEventListener('mousemove', updatePosition);
}, []);
return <h1>마우스 위치: X: {position.x}, Y: {position.y}</h1>;
}
✅ useEffect로 마우스 위치를 추적하여 실시간으로 화면에 표시합니다.
7. API 호출 및 데이터 로딩 상태 표시
import React, { useState, useEffect } from 'react';
function FetchWithLoading() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then((res) => res.json())
.then((json) => {
setData(json);
setLoading(false);
})
.catch((err) => console.error(err));
}, []);
if (loading) return <h2>로딩 중...</h2>;
return (
<ul>
{data.slice(0, 5).map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
✅ useEffect에서 API 데이터를 불러올 때 로딩 상태를 추가하여 사용자 경험을 개선합니다.
8. 채팅 앱에서 실시간 메시지 수신
import React, { useState, useEffect } from 'react';
function ChatApp() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const eventSource = new EventSource('https://example.com/chat');
eventSource.onmessage = (event) => {
setMessages((prev) => [...prev, JSON.parse(event.data)]);
};
return () => eventSource.close();
}, []);
return (
<ul>
{messages.map((msg, index) => (
<li key={index}>{msg.text}</li>
))}
</ul>
);
}
✅ 실시간 채팅 데이터를 수신하는 예제로, EventSource를 사용하여 WebSocket과 유사한 방식으로 데이터를 받습니다.
9. 탭 닫기 방지 기능
import React, { useEffect } from 'react';
function PreventExit() {
useEffect(() => {
const handleBeforeUnload = (event) => {
event.preventDefault();
event.returnValue = '';
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
}, []);
return <h1>이 페이지를 떠나면 데이터가 저장되지 않습니다.</h1>;
}
✅ useEffect를 활용해 브라우저 탭을 닫으려 할 때 경고 메시지를 표시합니다.
10. 스크롤 감지하여 버튼 숨기기
import React, { useState, useEffect } from 'react';
function ScrollToTop() {
const [showButton, setShowButton] = useState(false);
useEffect(() => {
const handleScroll = () => {
if (window.scrollY > 200) setShowButton(true);
else setShowButton(false);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<div>
{showButton && <button onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}>위로 가기</button>}
</div>
);
}
✅ useEffect로 스크롤 위치를 감지하여 버튼을 표시/숨김 처리합니다.
🎯 마무리 – useEffect 완벽 활용!
이제 useEffect의 개념과 다양한 실전 예제를 배웠습니다.
이 Hook을 활용하면 API 호출, 타이머, 이벤트 리스너, UI 상태 관리 등 다양한 기능을 쉽게 구현할 수 있습니다.
앞으로 React 프로젝트에서 적극 활용해보세요! 🚀
이 글이 도움이 되셨다면 좋아요 & 댓글 부탁드립니다! 😊
'React.js' 카테고리의 다른 글
[Dseok의 코딩스터디] React.js useMemo 한방에 끝내기 | 개념 & 실전 예제 7가지 (0) | 2025.03.05 |
---|---|
[Dseok의 코딩스터디] React.js useRef 한방에 끝내기 | 개념 & 실전 예제 9가지 (0) | 2025.03.04 |
[Dseok의 코딩스터디] React.js useState 한방에 끝내 – 기본 개념부터 15가지의 실전 예제 제공! React.js 19 (0) | 2025.02.28 |
[Dseok의 코딩스터디] React.js와 Express.js 연결하기 | 프론트엔드 & 백엔드 통합 (0) | 2025.02.24 |
[Dseok의 코딩스터디] 리액트에서 이미지 관리하는 방법 2가지 (1) | 2024.11.21 |