ReactJS - 컴포넌트 생명 주기
안녕하세요, 미래의 React 개발자 여러분! 오늘 우리는 React 컴포넌트의 생명 주기를 탐험하는 흥미로운 여정을 시작할 것입니다. 프로그래밍에 처음 접근하신 분이라도 걱정하지 마세요 - 저는 친절한 안내자로서 단계별로 모든 것을 설명해 드릴 것입니다. 이 튜토리얼이 끝나면 React 컴포넌트가 어떻게 탄생하고 성장하며, 결국 안녕을 인사하는지 잘 이해하실 수 있을 것입니다. 시작해 보겠습니다!
컴포넌트 생명 주기는 무엇인가요?
코드로 들어가기 전에 '생명 주기'라는 것에 대해 이야기해 보겠습니다. 우리 인간은 탄생, 성장, 그리고... 아시는대로... 등 다양한 단계를 거칩니다. React 컴포넌트 역시 자신만의 생명 단계를 가지고 있습니다. 이 단계를 컴포넌트 생명 주기라고 부릅니다.
React 컴포넌트를 가상의 애완동물로 생각해 보세요. 처음 만들어지면 탄생합니다. 그런 다음 상호작용을 통해 성장하고 변화합니다. 마지막으로 더 이상 필요하지 않을 때 사라집니다. 이 생명 주기를 이해하는 것은 동적인 및 효율적인 React 애플리케이션을 만들기 위해 매우 중요합니다.
컴포넌트의 세 가지 주요 단계
React 컴포넌트는 세 가지 주요 단계를 거칩니다:
- 마운트(탄생)
- 업데이트(성장)
- 언마운트(안녕)
이 각 단계와 관련된 메서드를 탐구해 보겠습니다.
1. 마운트 단계
이는 우리의 컴포넌트가 탄생하고 DOM(문서 객체 모델 - 웹 페이지의 가족 트리라고 상상해 보세요)에 추가되는 시기입니다.
이 단계의 주요 메서드:
메서드 | 설명 |
---|---|
constructor() | 컴포넌트가 마운트되기 전에 호출되는 컴포넌트의 생성자 |
render() | 실제로 컴포넌트를 렌더링하는 메서드 |
componentDidMount() | 컴포넌트가 DOM에 마운트된 후 호출됨 |
간단한 예제를 보겠습니다:
import React, { Component } from 'react';
class BabyComponent extends Component {
constructor(props) {
super(props);
this.state = { message: "저는刚刚 태어났어요!" };
console.log("생성자: 안녕하세요, 저는 만들어지고 있어요!");
}
componentDidMount() {
console.log("componentDidMount: 저는 이제 DOM에 들어갔어요!");
}
render() {
console.log("렌더링: 저는 렌더링되고 있어요!");
return <h1>{this.state.message}</h1>;
}
}
export default BabyComponent;
이 예제에서, 우리의 BabyComponent
는 탄생 단계를 거칩니다. constructor
가 먼저 호출되어 초기 상태를 설정합니다. 그런 다음 render
가 호출되어 실제 DOM 요소를 생성합니다. 마지막으로 componentDidMount
가 호출되어 컴포넌트가 완전히 탄생하고 DOM에 추가되었음을 알립니다.
2. 업데이트 단계
이 단계는 컴포넌트의 상태가 변경되거나 새로운 props를 받을 때 발생합니다.
이 단계의 주요 메서드:
메서드 | 설명 |
---|---|
shouldComponentUpdate() | 컴포넌트가 다시 렌더링해야 하는지 결정 |
render() | 업데이트된 데이터로 컴포넌트를 다시 렌더링 |
componentDidUpdate() | 컴포넌트가 업데이트된 후 호출됨 |
이전 예제를 확장해 보겠습니다:
import React, { Component } from 'react';
class GrowingComponent extends Component {
constructor(props) {
super(props);
this.state = { age: 0 };
}
componentDidMount() {
this.ageInterval = setInterval(() => {
this.setState(prevState => ({ age: prevState.age + 1 }));
}, 1000);
}
shouldComponentUpdate(nextProps, nextState) {
return nextState.age % 5 === 0; // 5년에 한 번씩 업데이트
}
componentDidUpdate() {
console.log(`저는 이제 ${this.state.age} 살이에요!`);
}
render() {
return <h1>저는 {this.state.age} 살입니다</h1>;
}
componentWillUnmount() {
clearInterval(this.ageInterval);
}
}
export default GrowingComponent;
이 예제에서, 우리의 GrowingComponent
는 매秒마다 "성장"합니다. shouldComponentUpdate
메서드는 5년에 한 번씩 생일을 축하합니다(케이크를 절약하려고요). 컴포넌트가 업데이트될 때마다 componentDidUpdate
가 생일 메시지를 로그합니다.
3. 언마운트 단계
이는 컴포넌트가 DOM에서 제거되는 이별 단계입니다.
이 단계의 주요 메서드:
메서드 | 설명 |
---|---|
componentWillUnmount() | 컴포넌트가 언마운트되고 파괴되기 직전에 호출됨 |
위의 GrowingComponent
예제에서, 우리는 componentWillUnmount
를 사용하여 인터벌을 清除하여 메모리 누수를 방지합니다.
생명 주기 API의 작동 예제
이제 모든 생명 주기 메서드를 하나의 더 복잡한 예제로 통합해 보겠습니다. 우리는 간단한 "기분 추적기" 애플리케이션을 만들어 보겠습니다.
import React, { Component } from 'react';
class MoodTracker extends Component {
constructor(props) {
super(props);
this.state = { mood: 'neutral', intensity: 5 };
console.log('생성자: 기분 추적기가 생성되고 있습니다');
}
componentDidMount() {
console.log('ComponentDidMount: 기분 추적기가 이제 DOM에 들어갔습니다');
this.moodInterval = setInterval(() => {
const moods = ['happy', 'sad', 'excited', 'nervous', 'neutral'];
const newMood = moods[Math.floor(Math.random() * moods.length)];
this.setState({ mood: newMood });
}, 5000);
}
shouldComponentUpdate(nextProps, nextState) {
return this.state.mood !== nextState.mood;
}
componentDidUpdate() {
console.log(`기분이 업데이트됨: ${this.state.mood}`);
}
componentWillUnmount() {
console.log('ComponentWillUnmount: 안녕 기분 추적기!');
clearInterval(this.moodInterval);
}
handleIntensityChange = (e) => {
this.setState({ intensity: e.target.value });
}
render() {
console.log('렌더링: 기분 추적기가 렌더링 중');
return (
<div>
<h1>현재 기분: {this.state.mood}</h1>
<input
type="range"
min="1"
max="10"
value={this.state.intensity}
onChange={this.handleIntensityChange}
/>
<p>강도: {this.state.intensity}</p>
</div>
);
}
}
export default MoodTracker;
이 MoodTracker
컴포넌트는 우리가 논의한 모든 생명 주기 메서드를 보여줍니다. 기분이 5초에 한 번씩 무작위로 변경되고, 사용자가 기분 강도를 조절할 수 있습니다.
지출 관리 애플리케이션에서 생명 주기 API 사용
이제 실제 애플리케이션에서 생명 주기 메서드를 어떻게 사용할 수 있는지 살펴보겠습니다. 예를 들어, 지출 관리 애플리케이션에서 사용할 수 있습니다.
import React, { Component } from 'react';
class ExpenseManager extends Component {
constructor(props) {
super(props);
this.state = { expenses: [], total: 0 };
}
componentDidMount() {
// API에서 지출 데이터를 가져오는 것을 시仿합니다
setTimeout(() => {
const fetchedExpenses = [
{ id: 1, description: '식료품', amount: 50 },
{ id: 2, description: '가스', amount: 30 },
{ id: 3, description: '영화 티켓', amount: 20 },
];
this.setState({ expenses: fetchedExpenses }, this.calculateTotal);
}, 1000);
}
shouldComponentUpdate(nextProps, nextState) {
// 총액이 변경되었을 때만 업데이트
return this.state.total !== nextState.total;
}
componentDidUpdate() {
console.log(`총 지출이 업데이트됨: $${this.state.total}`);
}
calculateTotal = () => {
const total = this.state.expenses.reduce((sum, expense) => sum + expense.amount, 0);
this.setState({ total });
}
render() {
return (
<div>
<h1>지출 관리</h1>
<ul>
{this.state.expenses.map(expense => (
<li key={expense.id}>{expense.description}: ${expense.amount}</li>
))}
</ul>
<h2>총액: ${this.state.total}</h2>
</div>
);
}
}
export default ExpenseManager;
이 ExpenseManager
컴포넌트에서:
-
componentDidMount
를 사용하여 컴포넌트가 처음 로드될 때 API에서 지출 데이터를 가져옵니다. -
shouldComponentUpdate
는 총액이 변경되었을 때만 렌더링을 업데이트합니다. -
componentDidUpdate
는 총액이 변경될 때마다 로그를 남깁니다.
이 생명 주기 메서드를 활용하면 효율적이고 반응성 있는 지출 추적 애플리케이션을 만들 수 있습니다.
컴포넌트 생명 주기를 이해하는 것은 효율적인 React 애플리케이션을 만들기 위해 매우 중요합니다. 이를 통해 특정 액션을 언제 발생시킬지, 성능을 최적화하고 자원을 효과적으로 관리할 수 있습니다. 이 개념을 계속 연습하면 곧 복잡하고 동적인 React 애플리케이션을 쉽게 만들 수 있을 것입니다!
Credits: Image by storyset