티스토리 뷰

리액트 개발자라면 반드시 이해해야 할 핵심 개념 중 하나가 바로 **생명주기(Lifecycle)**입니다. 컴포넌트가 브라우저에 나타나고, 업데이트되고, 사라지는 일련의 과정을 이해하면 보다 효율적인 앱을 설계할 수 있습니다.
과거에는 클래스형 컴포넌트의 메서드를 통해 이를 관리했지만, 현재는 React Hooks를 이용한 함수형 컴포넌트가 표준이 되었습니다. 이 글에서는 두 방식을 비교하며 생명주기를 완벽하게 정리해 보겠습니다.
1. 생명주기의 3단계 요약
리액트 컴포넌트의 생명주기는 크게 세 단계로 나뉩니다.
- Mounting (마운트): 컴포넌트가 DOM에 삽입될 때 (탄생)
- Updating (업데이트): Props나 State가 변경되어 재렌더링될 때 (성장)
- Unmounting (언마운트): 컴포넌트가 DOM에서 제거될 때 (소멸)
2. 클래스형 vs 함수형 비교 차트
단계클래스형 메서드함수형 Hook (useEffect)
| 마운트 | componentDidMount | useEffect(() => { ... }, []) |
| 업데이트 | componentDidUpdate | useEffect(() => { ... }, [의존성]) |
| 언마운트 | componentWillUnmount | useEffect(() => { return () => { ... } }) |
3. 단계별 상세 설명 및 실무 예제
① Mounting: 컴포넌트가 화면에 나타날 때
이 단계는 주로 외부 API 호출, 라이브러리 연동(D3, Google Maps 등), 혹은 setTimeout 같은 타이머를 설정할 때 사용됩니다.
[함수형 예제: API 데이터 불러오기]
import React, { useState, useEffect } from 'react';
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
// 마운트 시점에 딱 한 번 실행됨
console.log("컴포넌트가 마운트되었습니다.");
fetch('[https://api.example.com/user/1](https://api.example.com/user/1)')
.then(res => res.json())
.then(data => setUser(data));
}, []); // 빈 배열([])은 마운트 시에만 실행하라는 의미입니다.
return (
안녕하세요, {user.name}님!
:로딩 중...
} );
}
② Updating: 데이터가 변경되어 다시 그려질 때
특정 상태(state)나 속성(props)이 변경될 때 동작을 수행하고 싶다면 이 단계를 활용합니다.
[함수형 예제: 검색어 변경에 따른 재조회]
useEffect(() => {
if (searchTerm) {
console.log(`검색어가 "${searchTerm}"으로 변경되어 결과를 업데이트합니다.`);
// 검색 로직 실행
}
}, [searchTerm]); // searchTerm이 바뀔 때마다 실행됩니다.
③ Unmounting: 컴포넌트가 사라질 때
메모리 누수를 방지하기 위해 사용했던 이벤트 리스너를 제거하거나 타이머를 멈추는 '정리(Cleanup)' 작업이 필요합니다.
[함수형 예제: 타이머 해제]
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// Cleanup 함수: 언마운트 직전에 실행됨
return () => {
console.log("타이머를 종료하고 메모리를 정리합니다.");
clearInterval(intervalId);
};
}, []);
return <div>경과 시간: {seconds}초</div>;
}
4. 복합적인 흐름 이해하기
실무에서는 하나의 useEffect 안에서 마운트와 언마운트 로직을 동시에 처리하는 경우가 많습니다.
[종합 예제: 윈도우 리사이즈 이벤트]
function WindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
// 1. 마운트 시: 이벤트 등록
window.addEventListener('resize', handleResize);
console.log("리스너 등록");
// 2. 언마운트 시: 이벤트 제거
return () => {
window.removeEventListener('resize', handleResize);
console.log("리스너 해제");
};
}, []); // 의존성 배열이 비어있으므로 생성/소멸 시에만 작동
return <h2>현재 창 너비: {width}px</h2>;
}
5. 생명주기 관리 시 주의사항
- 의존성 배열 관리: useEffect의 두 번째 인자인 배열을 잘못 관리하면 무한 루프에 빠지거나 업데이트가 반영되지 않을 수 있습니다. 내부에 사용된 모든 상태값과 함수를 체크하세요.
- 불필요한 렌더링 방지: 매 렌더링마다 생명주기 로직이 실행되지 않도록 useMemo나 useCallback과 함께 사용하여 최적화하는 것이 좋습니다.
- Cleanup의 중요성: 외부 라이브러리를 연결했다면 반드시 언마운트 시점에 연결을 끊어주어야 성능 저하를 막을 수 있습니다.
리액트의 생명주기는 컴포넌트의 라이프 사이클을 개발자가 제어할 수 있게 해주는 강력한 도구입니다. 클래스형의 복잡한 메서드 이름보다는 useEffect 하나로 통합된 현대적인 리액트 방식을 익히는 것이 생산성 향상에 큰 도움이 됩니다.
'Frontend > React' 카테고리의 다른 글
| React 최적화: useMemo와 useCallback, 언제 쓰고 언제 말아야 할까? (0) | 2026.02.24 |
|---|---|
| useEffect 사용법 완벽 가이드: 입문부터 흔히 하는 실수까지 (0) | 2026.02.24 |
| 리액트 초보 탈출: Props vs State 5분 완성 가이드 (0) | 2026.02.24 |
| JSX란 무엇인가? HTML처럼 보이지만 다른 리액트의 핵심 문법 (0) | 2026.02.24 |
| 리액트 시작하기: npx create-react-app 없이 Vite로 5초 만에 환경 구축하기 (0) | 2026.02.24 |
- Total
- Today
- Yesterday
- CSR
- MSA
- It용어
- CSS
- 멀티모달
- java
- AI
- SSR
- 스마트안경
- TypeScript
- sLLM
- 협력
- HTML
- 카카오
- Nextjs
- on-device ai
- 웹기초
- HBM
- 구글
- LLM
- 엣지컴퓨팅
- prompt engineering
- Rag
- react
- Javascript
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |