React 생명주기(Lifecycle): 마운트(Mount)와 언마운트(Unmount)의 개념과 이해
1. 생명주기(Lifecycle)란?
React에서 **생명주기(lifecycle)**란 컴포넌트가 생성되고, 화면에 렌더링되며, 업데이트되고, 제거될 때까지의 일련의 과정을 의미합니다. React 컴포넌트는 이 생명주기 동안 특정 시점에 자동으로 호출되는 메서드나 함수들을 통해 상태 관리, 데이터 처리, 부수 효과(side effects) 등을 제어할 수 있습니다.
컴포넌트 생명주기는 크게 다음과 같은 단계로 구분됩니다:
- Mounting (마운트): 컴포넌트가 생성되어 DOM에 삽입되는 단계
- Updating (업데이트): 컴포넌트의 props나 state가 변경되어 재렌더링되는 단계
- Unmounting (언마운트): 컴포넌트가 DOM에서 제거되는 단계
이 중, 본 설명에서는 **마운트(Mount)**와 **언마운트(Unmount)**에 집중하여 설명하겠습니다.
2. 마운트(Mount)란?
2.1 정의
**마운트(Mount)**는 컴포넌트가 초기 생성되어 DOM에 추가되는 과정을 의미합니다. 즉, 화면에 처음으로 나타나는 시점입니다. 이 과정에서 컴포넌트는 다음과 같은 일을 합니다:
- props를 전달받음
- state 초기화 (클래스형: constructor, 함수형: useState)
- DOM 트리에 컴포넌트가 삽입됨
- 렌더링 수행
- 외부 API 호출, 이벤트 등록 등 부수 효과 실행
2.2 클래스형 컴포넌트의 마운트 생명주기 메서드
class MyComponent extends React.Component {
constructor(props) {
super(props); // 초기 props 설정
this.state = { count: 0 }; // 초기 state 설정
console.log('constructor');
}
componentDidMount() {
console.log('componentDidMount');
// API 호출, 이벤트 등록 등
}
render() {
console.log('render');
return <h1>Hello, world!</h1>;
}
}
호출 순서:
- constructor(): 컴포넌트 초기화, state 설정
- render(): JSX 반환
- componentDidMount(): 컴포넌트가 DOM에 삽입된 직후 호출됨
componentDidMount()는 특히 다음과 같은 작업에 적합합니다:
- API 데이터를 불러와 state에 저장
- 타이머 설정
- 외부 라이브러리 연동
- 이벤트 리스너 등록
2.3 함수형 컴포넌트에서의 마운트
React Hooks를 사용하는 함수형 컴포넌트에서는 useEffect()를 활용하여 마운트 타이밍을 처리합니다.
import React, { useEffect, useState } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
console.log('컴포넌트 마운트됨');
fetch('/api/data')
.then(res => res.json())
.then(result => setData(result));
}, []); // 빈 배열을 전달하면 마운트 시 1회 실행
return <div>{data ? data.name : 'Loading...'}</div>;
}
- useEffect(() => { ... }, []): 마운트 시점에 한 번만 실행됨
- 이 안에서 fetch, WebSocket 연결, 구독 등의 작업 수행
3. 언마운트(Unmount)란?
3.1 정의
**언마운트(Unmount)**는 컴포넌트가 DOM에서 제거되는 시점을 의미합니다. 페이지 이동, 조건부 렌더링 해제 등으로 인해 컴포넌트가 사라질 때 발생합니다.
언마운트 시에는 다음과 같은 작업이 필요할 수 있습니다:
- 타이머 제거 (clearInterval, clearTimeout)
- 이벤트 리스너 제거 (removeEventListener)
- WebSocket 종료, 구독 해제
- 메모리 누수 방지
3.2 클래스형 컴포넌트의 언마운트 메서드
class MyComponent extends React.Component {
componentWillUnmount() {
console.log('componentWillUnmount');
// 타이머 제거, 이벤트 제거 등
}
render() {
return <h1>Goodbye!</h1>;
}
}
- componentWillUnmount()는 컴포넌트가 제거되기 직전에 호출됩니다.
- 이 메서드는 주로 정리(clean-up) 작업에 사용됩니다.
3.3 함수형 컴포넌트에서의 언마운트 처리
useEffect() 내부에서 return 함수로 정리 작업을 할 수 있습니다. 이 return 함수는 컴포넌트가 언마운트될 때 실행됩니다.
import React, { useEffect } from 'react';
function TimerComponent() {
useEffect(() => {
const timer = setInterval(() => {
console.log('타이머 실행');
}, 1000);
return () => {
clearInterval(timer); // 컴포넌트 언마운트 시 타이머 제거
console.log('컴포넌트 언마운트됨');
};
}, []);
return <div>1초마다 로그 출력 중</div>;
}
이렇게 return 함수를 통해 컴포넌트가 사라지기 직전에 해야 할 정리 작업을 명확히 관리할 수 있습니다.
4. 마운트 & 언마운트의 실전 예시
function ChatRoom({ roomId }) {
useEffect(() => {
const connect = () => console.log(`방 ${roomId}에 연결`);
const disconnect = () => console.log(`방 ${roomId} 연결 해제`);
connect();
return () => {
disconnect(); // 언마운트 시 정리
};
}, [roomId]);
return <h1>{roomId}번 채팅방</h1>;
}
- roomId가 바뀔 때마다 이전 연결을 해제하고 새로 연결
- 이 방식은 실시간 통신, 소켓 연결 등에서 매우 중요
5. 요약 정리
구분 마운트(Mount) 언마운트(Unmount)
| 정의 | 컴포넌트가 DOM에 삽입되는 과정 | 컴포넌트가 DOM에서 제거되는 과정 |
| 클래스형 메서드 | constructor, componentDidMount | componentWillUnmount |
| 함수형 Hook | useEffect(() => {...}, []) | useEffect(() => {...}; return () => {...}, []) |
| 주요 작업 | API 호출, 초기화, 구독 시작 | 타이머 제거, 구독 해제, 메모리 정리 |
| 사용 예 | 초기 데이터 로딩, 이벤트 등록 | 자원 정리, 소켓 연결 종료 |
6. 결론
React의 마운트와 언마운트는 컴포넌트의 시작과 종료를 제어하는 중요한 개념입니다. 이를 제대로 이해하면 부수 효과를 안전하게 관리할 수 있으며, 메모리 누수나 성능 저하 문제를 사전에 방지할 수 있습니다. 함수형 컴포넌트에서는 useEffect()를 중심으로 이러한 생명주기를 통제하며, 클래스형에서는 각 메서드를 통해 세밀하게 생애주기를 관리할 수 있습니다.