Redux(전역 상태 관리 라이브러리)

민경빈·2025년 11월 19일

전역 상태 관리

프론트엔드에서 애플리케이션이 복잡해질수록 “상태 관리”는 개발 난이도를 결정하는 핵심 요소가 된다.
초기 React에서는 각 컴포넌트 내부에서 state를 관리해도 큰 문제가 없었지만, 애플리케이션 규모가 커지는 순간 상황은 완전히 달라진다.

이 글에서는 Redux가 등장한 이유, 핵심 동작 원리, Redux Toolkit, 그리고 그 토대가 되는 개념인 전역 상태 관리(Global State Management)까지 한 번에 정리한다.


1. 전역 상태 관리란?

애플리케이션 내의 상태(state)는 크게 두 가지로 나뉜다.

🔹 로컬 상태(Local State)

특정 컴포넌트 내부에서만 사용하는 값
예: 모달 열림/닫힘, input 입력값, 개별 UI 선택 상태 등

🔹 전역 상태(Global State)

여러 컴포넌트에서 동시에 사용하는 값
예:

  • 로그인 여부(isLoggedIn)
  • 로그인 사용자 정보(user)
  • 장바구니 목록(cartItems)
  • UI 테마(다크/라이트)
  • 필터 조건(filterOptions)

React 기본 구조에서 이를 관리하려고 하면 props drilling 문제가 발생한다.
또한 여러 위치에서 동일한 데이터를 각각 관리하면 데이터 일관성(Inconsistency)이 쉽게 깨진다.

따라서 애플리케이션 전반에서 공통으로 쓰이는 데이터는 한 곳에서 관리해야 한다.
이를 전역 상태 관리(Global State Management)라고 한다.

그리고 Redux는 이러한 전역 상태 문제를 체계적으로 해결하는 도구다.


2. Redux란 무엇인가?

Redux는 전역 상태를 예측 가능하게 관리하기 위한 상태 관리 라이브러리이다.
주로 React와 함께 사용되지만, 특정 프레임워크에 종속되지 않으며
어떤 JavaScript 환경에서도 사용할 수 있다.

Redux의 핵심 철학은 다음 세 가지이다.

  1. 모든 전역 상태는 하나의 저장소(Store)에 존재해야 한다.
  2. 상태는 직접 수정할 수 없으며, action을 통해서만 변경된다.
  3. 상태 변경 로직은 순수 함수(Reducer)로 정의되어야 한다.

3. Redux가 필요한 이유

React만으로도 상태 관리는 가능하지만, 애플리케이션의 규모가 커질수록 문제점이 드러난다.

1. props drilling 문제

상태를 전달하기 위해 부모 → 자식 → 손자 컴포넌트로 이어지는 불필요한 props가 계속 등장한다.
이 과정은 컴포넌트 구조를 복잡하게 만들고 유지보수를 어렵게 한다.

2. 전역 데이터의 중복 관리

여러 컴포넌트에서 동일한 데이터를 각각 관리하게 되면, 상태가 서로 일치하지 않는 문제가 발생한다.
이런 상태 불일치는 디버깅이 어려운 버그로 이어진다.

3. 상태 변경 흐름 추적의 어려움

상태가 여러 곳에서 변경되면 어떻게 바뀐 것인지 추적하기가 어렵다.
애플리케이션이 커질수록 이러한 문제는 더욱 복잡해진다.

Redux는 이 모든 문제를 해결하기 위해 설계된 라이브러리이다.
전역 상태의 흐름을 단일한 규칙 아래 통제하여 상태 변화를 예측 가능하게 만든다.


4. Redux의 핵심 요소

Redux는 네 가지 주요 요소로 구성된다.

1. Store

애플리케이션의 모든 전역 상태가 저장되는 중앙 저장소이다.
store는 단 하나만 존재하며, 전역 상태의 단일 출처 역할을 한다.

2. Action

상태를 어떻게 변경할 것인지를 설명하는 “의도(intent)” 객체이다.

{ type: "cart/addItem", payload: item }

3. Reducer

action을 받아 실제로 상태를 변경하는 순수 함수이다.
상태 변경 로직은 reducer 내부에서 정의된다.


function cartReducer(state, action) {
  switch (action.type) {
    case "cart/addItem":
      return [...state, action.payload];
    default:
      return state;
  }
}

Reducer는 기존 상태를 직접 수정하지 않고,
항상 새로운 상태 객체를 반환한다는 점이 중요하다.

4. Dispatch

dispatch는 action을 store로 전달하는 함수이다.
UI에서 발생한 이벤트를 store로 보내는 통로라고 보면 된다.

dispatch({ type: "cart/addItem", payload: item });

dispatch가 호출되면 reducer가 실행되어 새로운 상태가 계산되고,
이를 기반으로 UI가 다시 렌더링된다.

5. Redux의 데이터 흐름

Redux는 단방향 데이터 흐름(one-way data flow)을 사용한다.

UI → Action → Dispatch → Reducer → Store → UI 업데이트

이 단일 흐름 덕분에 상태가 언제, 어떻게 바뀌었는지 쉽게 추적할 수 있다.
또한 데이터 흐름이 너무 복잡해지는 것을 방지하여 애플리케이션의 안정성을 높인다.

6. Redux 예시

아래는 간단한 Counter 예시이다.

Action

{ type: "counter/increment" }

Reducer

function counterReducer(state = { value: 0 }, action) {
  switch (action.type) {
    case "counter/increment":
      return { value: state.value + 1 };
    default:
      return state;
  }
}

Dispatch


dispatch({ type: "counter/increment" });

7. Redux Toolkit(RTK)의 등장

기존 Redux는 강력했지만, 실제 사용 과정에서 다음과 같은 불편함이 있었다.

action type 문자열을 매번 작성해야 함 / action creator 함수를 직접 만들어야 함 /reducer에서 불변성 관리를 일일이 처리해야 함
이 문제를 해결하기 위해 등장한 것이 Redux Toolkit(RTK)이다.
RTK는 다음 기능을 자동으로 처리한다.

1.action type 및 action creator 자동 생성
2.불변성 관리 자동화 (Immer 기반)
3.thunk 내장
4.slice 구조로 파일 단순화

Redux Toolkit은 현대 Redux 개발의 사실상 표준이며, 새로운 Redux 프로젝트는 대부분 RTK를 사용한다.

8. Redux를 언제 사용하나

Redux는 강력한 도구이지만, 모든 프로젝트에 필요한 것은 아니다.

✔ Redux가 적합한 경우

애플리케이션 규모가 크고 상태가 복잡할 때

여러 컴포넌트에서 동일한 데이터를 공유할 때

상태 변경 이력을 명확하게 추적해야 할 때

DevTools를 통한 디버깅이 중요한 프로젝트일 때

❌ Redux가 필요 없는 경우

상태가 간단한 소규모 프로젝트

전역 상태가 거의 없을 때

서버 상태가 중심인 프로젝트 (TanStack Query가 적합)

Redux는 전역 상태 관리 문제를 가장 체계적으로 해결한 라이브러리이다.
특히 Redux Toolkit의 등장 이후 Redux는 훨씬 간결해지고 사용성이 좋아졌다.
전역 상태가 많고, 여러 컴포넌트에서 공유되며,상태 변경 과정을 예측 가능하게 유지하고 싶다면Redux는 지금도 여전히 매우 좋은 선택지다.

0개의 댓글