서론
웹 애플리케이션을 만들다 보면 화면이 사용자와 상호작용하면서 계속 바뀌는 상황을 자주 마주하게 됩니다. 사용자가 버튼을 클릭하거나, 데이터를 입력하거나, 서버로부터 응답을 받을 때마다 애플리케이션은 그에 따라 다른 동작을 해야 합니다. 이런 변화들을 가능하게 해주는 핵심 개념이 상태(state)입니다.
상태라는 개념을 처음 접할 때 추상적으로 느껴질 수 있고, 왜 상태를 관리 해야할까? 라는 고민이 들 수 있습니다. 이 글에서는 상태란 무엇인지, 왜 상태관리가 필요하며, 어떻게 다룰 수 있는지 정리해보았습니다.
상태란?
상태(state)란 애플리케이션이 특정 시점에 가지고 있는 데이터나 정보, 그리고 그에 따라 달라지는 화면(UI)의 모습을 말합니다. 쉽게 말하면, 애플리케이션이 지금 어떤 상황인지를 나타내는 값이라 할 수 있습니다. 이 값은 사용자 입력, 서버 응답, 내부 로직 등에 의해 언제든지 바뀔 수 있으며, 그에 따라 애플리케이션의 동작이나 화면도 함께 변화합니다.
조금 더 이론적으로 설명하자면, 상태는 시간의 흐름에 따라 변경될 수 있는 값이며, 애플리케이션의 흐름과 구조를 결정하는 핵심 요소입니다. 상태는 단순한 값 그 자체를 넘어서, 애플리케이션의 기능이 어떻게 반응하고 작동하는지를 정의하는 기준이 되기도 합니다.
예를 들어 아래와 같은 것들이 모두 상태에 해당됩니다.
- 버튼을 눌렀을 때 증가하는 숫자 (예: 카운터)
- 사용자가 입력한 로그인 정보
- 로그인 여부 (로그인됨 / 로그아웃됨)
- 장바구니에 담긴 상품 목록
- 서버에서 받아온 데이터 (예: 게시글 목록)
- 현재 선택된 탭이나 모달의 열림 여부 등 UI 상태
즉, 애플리케이션 안에서 변화하며 사용자 경험과 직접적으로 연결되는 모든 값들은 상태라고 볼 수 있습니다.
상태를 왜 관리해야 할까?
간단한 기능이라면 변수 하나로도 충분할 수 있습니다. 하지만 애플리케이션이 점점 복잡해질수록 다음과 같은 문제가 발생하기 시작합니다.
- 컴포넌트 간 상태 공유의 어려움: 화면의 여러 부분에서 동일한 상태를 참고하고 업데이트해야 하는 경우,그 흐름을 추적하고 일관되게 유지하기가 어렵습니다.
- 예측하기 힘든 버그: 상태가 흩어져 있거나 변경 흐름이 불분명하면 디버깅이 복잡해집니다.
- 렌더링 또는 UI 업데이트 최적화 문제: 불필요하게 많은 요소가 갱신되며 성능 저하로 이어질 수 있습니다.
- 동기화 문제: 사용자 입력, 네트워크 요청, UI 상태 등이 서로 비동기적으로 처리되며 충돌이 발생할 수 있습니다.
이처럼 상태가 많아질수록 체계적으로 관리하지 않으면 유지보수가 힘들어지고, 버그가 생길 가능성이 높아집니다.
순수 Javascript에서의 상태관리
라이브러리나 프레임워크 없이도 웹 애플리케이션에서 상태를 관리할 수 있습니다. 순수 JavaScript에서는 변수에 값을 저장하고, 이벤트를 바인딩한 뒤 직접 DOM을 조작하는 방식으로 상태를 표현하고 갱신합니다. 즉, 값의 변화와 그에 따른 UI 업데이트를 모두 개발자가 수동으로 처리해야 하며, 이 과정을 통해 애플리케이션의 흐름을 제어합니다.
이러한 방식은 구조가 단순한 프로젝트에서는 충분히 효과적일 수 있습니다. 그러나 복잡한 상태가 많아지면, 상태 간의 관계를 추적하고 효율적으로 관리하는 것이 점점 어려워지기도 합니다.
로컬 상태 (Local State)
- 특정 UI나 기능에서만 사용되는 상태입니다.
- 예: 페이지 내 버튼 클릭 수, 입력 필드 값 등
let count = 0;
const button = document.getElementById('increment');
const display = document.getElementById('count');
button.addEventListener('click', () => {
count++;
display.innerText = count;
});
전역 상태 (Global State)
- 여러 UI 요소나 페이지 간 공유되는 상태입니다.
- 예: 로그인 여부, 다크모드 설정 등
const globalState = {
isLoggedIn: false
};
function login() {
globalState.isLoggedIn = true;
updateUI();
}
function updateUI() {
if (globalState.isLoggedIn) {
document.body.classList.add('authenticated');
}
}
서버 상태 (Server State)
- 서버와의 통신으로 받아오는 데이터입니다.
- 비동기적으로 데이터를 받고, 로딩 중/성공/실패 상태도 함께 관리해야 합니다.
let isLoading = true;
let data = null;
fetch('/api/posts')
.then(response => response.json())
.then(json => {
isLoading = false;
data = json;
renderPosts(data);
});
프레임워크/라이브러리 없이 상태를 관리할 때의 한계
- 상태와 UI를 일일이 수동으로 연결해야 합니다.
- 상태 변경에 따라 어떤 UI를 업데이트할지 직접 지정해야 합니다.
- 비동기 처리 및 사이드 이펙트 관리가 복잡합니다.
- 규모가 커질수록 관리 포인트가 기하급수적으로 늘어납니다.
이런 이유로, 일정 규모 이상의 애플리케이션에서는 상태관리 도구를 도입하게 됩니다.
라이브러리, 프레임워크별 상태관리 방식
React
React에서는 useState나 useReducer 같은 훅(Hook)을 이용해 컴포넌트 내부의 상태를 다룹니다. 상태가 단순할 때는 useState만으로도 충분하지만, 조금 더 복잡한 로직이 필요한 경우에는 useReducer를 선택하는 것이 좋습니다. 여러 컴포넌트에서 상태를 공유해야 한다면 Context API를 사용할 수 있지만, 상태의 규모가 커지면 Redux, Zustand, Recoil 같은 외부 라이브러리를 사용하는 것이 더 안정적입니다.
또한 서버에서 데이터를 가져와야 하는 경우, React Query나 SWR과 같은 도구를 함께 쓰면 로딩 상태, 에러 처리, 캐싱 등을 훨씬 수월하게 관리할 수 있습니다.
Vue
Vue에서는 data 속성을 통해 상태를 정의하고, computed와 watch를 이용해 상태 변화에 반응할 수 있습니다. Vue 3부터는 Composition API가 도입되면서 ref와 reactive 같은 도구를 활용해 상태를 좀 더 유연하게 다룰 수 있게 되었습니다.
전역 상태 관리가 필요할 때는 Vuex가 많이 사용되었지만, 최근에는 문법이 간단하고 학습 부담이 적은 Pinia가 공식적으로 추천되고 있습니다.
Svelte
Svelte는 특별한 API 없이도 변수 선언만으로 상태가 반응형으로 동작합니다. 예를 들어 변수에 값을 할당하면 자동으로 관련 UI가 갱신됩니다.
복잡한 계산이 필요한 경우에는 $: 구문을 사용해 파생 상태를 정의할 수 있으며, 여러 컴포넌트에서 공유할 상태는 store라는 구조를 통해 전역으로 관리할 수 있습니다.
상태관리 도구는 어떤 역할을 할까?
- 자동 UI 갱신: 상태가 바뀌면 관련된 UI를 자동으로 갱신합니다.
- 상태 추적: 상태의 변경 기록 추적이 가능하여 디버깅이 쉽게 만들어줍니다.
- 전역 상태 공유: 여러 화면에서 손쉽게 상태를 공유하고 갱신합니다.
- 비동기 처리 관리: 서버 요청과 관련된 상태도 함께 처리 할 수 있습니다.
마무리
상태는 애플리케이션의 모든 흐름과 연결된 핵심 요소입니다. UI의 동작부터 서버와의 데이터 처리까지, 결국은 상태가 어떻게 구성되고 관리되느냐에 따라 애플리케이션의 안정성과 유지보수성이 달라지게 됩니다.
규모가 작을 때는 간단한 변수나 직접적인 DOM 조작만으로도 충분하지만, 기능이 많아지고 사용자와의 상호작용이 복잡해질수록 체계적인 상태 관리가 필요해집니다. 중요한 건 어떤 상황에서 어떤 방식이 적절한지를 판단할 수 있는 기준을 갖는 것이며, 이를 통해 더 나은 구조와 사용자 경험을 설계할 수 있다고 생각합니다.
'FrontEnd' 카테고리의 다른 글
왜 지금도 React를 사용할까? (0) | 2025.04.11 |
---|---|
웹 실시간 통신에 대해서 알아보자 (0) | 2025.04.09 |
BFF(BackEnd-For-FrontEnd)란 무엇일까? (0) | 2025.04.08 |
웹 접근성에 대해서 알아보기 (0) | 2025.04.06 |
WebP와 AVIF를 알아보기 (0) | 2025.04.06 |