React의 상태(state)는 UI가 사용자 입력이나 데이터 변경에 따라 동적으로 업데이트될 수 있도록 도와주는 핵심 개념입니다. React는 2013년 오픈 소스로 공개된 이후로 지속적으로 발전해왔으며, 상태 관리 방식도 변화해왔는데요. 🤔
이번 글에서는 클래스형 컴포넌트에서의 state 개념과 그 한계를 살펴보고, 함수형 컴포넌트에서
useState
훅이 등장하면서 상태 관리가 어떻게 변화했는지 알아보겠습니다!
초기 웹 개발에서는 정적인 HTML과 CSS만으로 웹페이지를 구성했습니다. 하지만 사용자 인터랙션이 증가하면서, 동적인 UI를 관리할 수 있는 방법이 필요해졌습니다. React가 등장하기 전에는 jQuery와 같은 라이브러리를 사용하여 DOM을 직접 조작하는 방식이 일반적이었습니다. 하지만 이러한 방식은 코드가 복잡해지고, 상태를 일관성 있게 관리하기 어려운 문제점을 가지고 있었습니다.
💡 React는 이러한 문제를 해결하기 위해 Virtual DOM과 컴포넌트 기반 개발 방식을 도입하였고, 각 컴포넌트가 자체적으로 상태를 관리할 수 있도록 state
개념을 제공했습니다. 이를 통해 UI 변경 사항을 React 내부에서 자동으로 처리할 수 있게 되었고, 효율적인 렌더링이 가능해졌죠.
React가 처음 등장했을 때, 상태 관리는 주로 클래스형 컴포넌트에서 이루어졌습니다. 클래스형 컴포넌트에서는 this.state
를 통해 상태를 정의하고, this.setState()
를 사용하여 상태를 변경했습니다.
클래스형 컴포넌트에서의 state 사용 예시
import React, { Component } from "react";
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>현재 카운트: {this.state.count}</p>
<button onClick={this.increment}>증가</button>
</div>
);
}
}
export default Counter;
위 예제에서는 constructor
에서 초기 상태를 설정하고, setState
를 이용해 상태를 업데이트합니다. 하지만 클래스형 컴포넌트는 코드가 길어지고 this 바인딩 문제 등으로 인해 개발이 번거롭다는 단점을 가지고 있었죠.
위처럼 클래스형 컴포넌트는 강력한 기능을 제공하지만 몇 가지 단점이 있었습니다.
복잡한 문법: this 바인딩이 필요하며, 상태 관리 로직이 클래스 내부에서 분산되어 유지보수가 어렵다.
재사용성 부족: 클래스형 컴포넌트에서 상태 관련 로직을 재사용하려면 고차 컴포넌트(HOC)나 렌더 프롭(Render Props) 패턴을 사용해야 했으며, 이는 코드 가독성을 낮춘다다.
번거로운 라이프사이클 관리: componentDidMount, componentDidUpdate, componentWillUnmount 등 다양한 라이프사이클 메서드를 사용해야 했으며, 서로 관련된 로직이 분산되어 있다.
이러한 문제를 해결하기 위해 React 16.8(2019년)에서 함수형 컴포넌트와 훅(Hook) 개념이 도입되었습니다.
그중 가장 대표적인useState
훅을 사용하면 클래스형 컴포넌트 없이도 상태 관리를 할 수 있으며, 코드가 더욱 간결해졌습니다 :)
함수형 컴포넌트에서의 useState 사용 예시
import React, { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>현재 카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
};
export default Counter;
위 코드에서 useState(0)
은 count의 초기 상태를 0으로 설정합니다. setCount
함수를 호출하면 상태가 업데이트되며, React는 변경된 상태를 반영해 UI를 다시 렌더링합니다.
React의 state
가 변경되면 UI가 자동으로 렌더링됩니다. 이는 React 내부의 Virtual DOM과 렌더링 최적화 덕분이죠.
초기 렌더링
useState(0)
을 호출하면 React 내부에서 count의 상태 값을 0으로 저장합니다. 이 상태를 기반으로 UI가 렌더링됩니다.상태 변경 및 업데이트
사용자가 버튼을 클릭하면 setCount(count + 1)
이 실행됩니다.
React는 setCount
를 호출하면 내부적으로 새로운 상태 값을 저장하고, 변경된 상태를 감지합니다.
Virtual DOM 비교 및 렌더링 최적화
React는 이전 상태와 새로운 상태를 비교하여 변경된 부분만 Virtual DOM에서 갱신합니다.
변경된 부분을 실제 DOM에 반영하여 불필요한 전체 페이지 렌더링을 방지하고 성능을 최적화합니다.
UI 업데이트
지금까지 React의 상태(state)가 왜 필요했는지, 클래스형 컴포넌트와 함수형 컴포넌트에서의 상태 관리 방식이 어떻게 변화해왔는지를 살펴봤습니다.
이처럼 React는 초기에는 클래스형 컴포넌트를 중심으로 상태를 관리했지만, useState
와 같은 훅의 등장으로 함수형 컴포넌트에서도 간결하고 직관적인 상태 관리가 가능해졌습니다. 결국, React의 상태 관리는 단순히 데이터를 저장하는 것뿐만 아니라, 동적인 UI를 효율적으로 업데이트하고 유지보수하기 쉽게 만드는 중요한 개념입니다.
요즘은 대부분 함수형 컴포넌트와 훅을 활용해 개발하는 만큼, useState
뿐만 아니라 useEffect
, useReducer
같은 다양한 훅도 함께 사용하여 더 유연하게 상태를 관리하고 있죠! 앞으로도 React의 상태 관리 방식은 계속 발전할 것이므로, 변화하는 흐름을 꾸준히 따라가며 익혀두는 것이 중요할 것 같습니다 :)