useEffect는 다양한 상황에서 활용되지만, 실무에서 특히 자주 사용되는 대표적인 예시 몇 가지를 소개한다.
1. 📊 컴포넌트 마운트 시 초기 데이터 로딩
- 상황: 페이지나 특정 컴포넌트가 처음 화면에 나타날 때, 서버로부터 필요한 초기 데이터 목록(예: 상품 목록, 게시글 목록, 초기 설정값 등)을 가져와야 하는 경우.
- 구현:
- useEffect의 콜백 함수 내에서 데이터 요청 함수(API 호출)를 실행한다.
- **의존성 배열은 빈 배열([])**로 설정하여, 컴포넌트가 최초 렌더링(마운트) 될 때 한 번만 실행되도록 한다.
- 가져온 데이터는 useState를 사용하여 상태에 저장하고 화면에 표시한다.
- 예시 개념:
JavaScript
const [items, setItems] = useState([]); const [isLoading, setIsLoading] = useState(true); useEffect(() => { // 데이터 가져오는 비동기 함수 (async/await 사용 예시) const fetchItems = async () => { setIsLoading(true); // 로딩 시작 try { const response = await fetch('/api/items'); // API 호출 const data = await response.json(); setItems(data); // 상태 업데이트 } catch (error) { console.error("데이터 로딩 실패:", error); // 에러 처리 로직 } finally { setIsLoading(false); // 로딩 종료 } }; fetchItems(); // 함수 실행 }, []); // 빈 배열: 마운트 시 1회만 실행
- 목적: 컴포넌트가 준비되는 시점에 필요한 데이터를 효율적으로 불러온다.
2. 👤 특정 값 변경 시 데이터 다시 로딩
- 상황: 사용자의 프로필 페이지처럼, 특정 ID 값(props로 전달받거나 URL 파라미터에서 가져온 값)에 따라 다른 데이터를 서버에서 가져와 보여줘야 하는 경우.
- 구현:
- useEffect의 콜백 함수 내에서 해당 ID를 인자로 사용하여 데이터 요청 함수를 호출한다.
- 의존성 배열에 해당 ID 값 ([userId])을 넣어준다. 이렇게 하면 userId 값이 변경될 때마다 이펙트 함수가 다시 실행되어 새로운 사용자의 데이터를 불러온다.
- ID 값이 유효할 때만 API를 호출하도록 조건문을 추가하는 것이 좋다.
- 예시 개념:
JavaScript
const [userData, setUserData] = useState(null); const { userId } = useParams(); // URL 파라미터에서 userId 가져오기 (react-router-dom 예시) useEffect(() => { const fetchUserData = async (id) => { if (!id) return; // userId가 없으면 실행 중단 // 로딩 상태 관리 추가... try { const response = await fetch(`/api/users/${id}`); const data = await response.json(); setUserData(data); } catch (error) { console.error("사용자 데이터 로딩 실패:", error); } }; fetchUserData(userId); // 함수 실행 }, [userId]); // userId가 변경될 때마다 이펙트 재실행
- 목적: 동적인 값(ID, 검색어 등)의 변경에 반응하여 관련된 데이터를 업데이트한다.
3. 🖥️ 브라우저 API 연동 (예: 이벤트 리스너)
- 상황: window 객체의 resize(창 크기 변경)나 scroll(스크롤 위치 변경) 이벤트를 감지하여 특정 동작(예: 레이아웃 변경, 스크롤 위치에 따른 효과 적용)을 수행해야 하는 경우.
- 구현:
- useEffect의 콜백 함수 내에서 window.addEventListener를 사용하여 이벤트 리스너를 등록한다.
- **의존성 배열은 빈 배열([])**로 설정하여 마운트 시 한 번만 등록한다.
- 정리(cleanup) 함수를 반드시 반환하여, 컴포넌트가 언마운트될 때 window.removeEventListener를 통해 등록했던 리스너를 제거해준다. (메모리 누수 방지)
- 예시 개념:
JavaScript
const [windowWidth, setWindowWidth] = useState(window.innerWidth); useEffect(() => { const handleResize = () => { setWindowWidth(window.innerWidth); // 창 너비 상태 업데이트 }; window.addEventListener('resize', handleResize); // 리스너 등록 // 정리 함수: 컴포넌트 언마운트 시 리스너 제거 return () => { window.removeEventListener('resize', handleResize); }; }, []); // 빈 배열: 마운트 시 1회만 등록, 언마운트 시 1회만 제거
- 목적: 리액트 외부 환경(브라우저 API)과 상호작용하고, 컴포넌트 생명주기에 맞춰 리소스를 안전하게 관리한다.
4. ⏰ 타이머 설정 및 해제
- 상황: 일정 시간 간격으로 특정 작업을 수행(예: 데이터 폴링, 슬라이드 쇼 자동 넘김)하거나, 일정 시간 후에 특정 동작을 수행(예: 알림 메시지 자동 닫기)해야 하는 경우.
- 구현:
- useEffect의 콜백 함수 내에서 setInterval이나 setTimeout을 사용하여 타이머를 설정한다.
- 의존성 배열은 타이머를 언제 재시작할지에 따라 설정한다 (보통 []로 한 번만 실행).
- 정리(cleanup) 함수에서 clearInterval이나 clearTimeout을 호출하여, 컴포넌트 언마운트 시 타이머를 반드시 해제한다.
- 예시 개념: (1초마다 카운트 증가)
JavaScript
const [count, setCount] = useState(0); useEffect(() => { const intervalId = setInterval(() => { setCount(prevCount => prevCount + 1); // 이전 상태 기반 업데이트 권장 }, 1000); // 1초 간격 // 정리 함수: 언마운트 시 인터벌 해제 return () => { clearInterval(intervalId); }; }, []); // 빈 배열: 마운트 시 1회만 인터벌 설정
- 목적: 시간 기반의 작업을 컴포넌트 생명주기와 동기화하여 관리한다.
이 외에도 useEffect는 외부 라이브러리 연동, 로컬 스토리지 접근 등 다양한 사이드 이펙트를 처리하는 데 필수적으로 사용되는 강력한 도구다. 중요한 것은 의존성 배열을 올바르게 설정하고, 필요한 경우 정리 함수를 통해 리소스를 관리하는 것이다.
소스 및 관련 콘텐츠
'리액트 > 기초' 카테고리의 다른 글
React Context API 사용 가이드 (0) | 2025.04.09 |
---|---|
✨ useMemo 란? (0) | 2025.04.07 |
⚙️ useState 주요 활용 사례 (0) | 2025.04.07 |
리액트 기초 01 - 핵심 요소 3 - Hooks : useState란 무엇인가? (0) | 2025.04.07 |
리액트 기초 01 - 핵심 요소 3 - Hooks (0) | 2025.04.07 |