Redux: React Native에서 상태 관리 패턴 이해하기

저자: IT Sectr 게시일: 2026-02-19 읽는 시간: 8 분

Redux는 Dan Abramov가 2015년에 만든 JavaScript 애플리케이션을 위한 예측 가능한 상태 관리 컨테이너입니다. Redux는 Flux 아키텍처를 기반으로 단방향 데이터 흐름을 구현합니다. 상태는 단일 Store에 저장되고, 순수 Reducer 함수를 통해서만 변경되며, Dispatch와 함께 Action을 통해 시작됩니다. npm Trends에 따르면 Redux는 주간 700만 회 이상의 다운로드를 유지하며 React Native 및 웹 애플리케이션에서 상태 관리의 표준으로 남아 있습니다.

핵심 포인트

  • Store — 유일한 진실 공급원, 전체 애플리케이션 상태 트리 저장
  • Action — type 필드를 가진 객체, 상태 변경 의도 설명
  • Reducer — 부작용 없는 순수 함수 (prevState, action) => newState
  • Dispatch — Action을 Reducer로 보내는 Store 메서드
  • Middleware — 비동기 작업 및 로깅을 위한 dispatch와 reducer 사이의 계층

Redux란?

Redux는 세 가지 원칙에 기반한 아키텍처 패턴이자 상태 관리 라이브러리입니다: 유일한 진실 공급원, 읽기 전용 상태, 순수 함수를 통한 변경. 모델이 예측 불가능하게 상태를 변경할 수 있는 MVC와 달리 Redux는 결정론을 보장합니다: 동일한 입력 데이터에 대해 결과는 항상 동일합니다.

Redux는 Facebook의 Flux 아키텍처와 Elm 언어에서 영감을 받았습니다. Flux와의 주요 차이점은 여러 개 대신 단일 Store를 사용한다는 것입니다. Redux에서는 모든 애플리케이션 상태(객체, 배열, 로딩 플래그)가 하나의 트리에 저장됩니다. 이는 디버깅, 테스트 및 시간 여행 디버깅을 단순화합니다. 개발자는 전체 Store를 저장하고, Action 시퀀스를 재생하며, 각 단계에서 상태가 어떻게 변경되었는지 확인할 수 있습니다.

State of JS 2025 설문 조사에 따르면 상태 관리를 사용하는 응답자의 68%가 Redux 또는 Redux Toolkit을 선택합니다. 이 도구는 React, React Native, Angular, Vue 및 프레임워크 없는 바닐라 JavaScript를 포함한 모든 최신 프레임워크에서 지원됩니다.

단방향 데이터 흐름

단방향 데이터 흐름은 Redux의 핵심 원칙으로, 데이터가 엄격하게 한 방향으로 이동합니다: View → Action → Dispatch → Reducer → Store → View. 어떤 컴포넌트도 Store를 직접 변경할 수 없습니다. View는 useSelector 또는 connect를 통해 변경 사항을 구독하고 dispatch를 통해 변경을 시작합니다.

Redux 워크플로우 사이클: 사용자가 버튼을 클릭 → 컴포넌트가 dispatch({ type: 'INCREMENT' }) 호출 → Store가 Action을 Root Reducer로 전달 → Reducer가 새 상태 계산 → Store가 구독자에게 알림 → View가 새 데이터로 다시 렌더링. 이 사이클은 각 변경 사항이 특정 Action의 형태로 명시적 원인을 가지도록 보장합니다.

DevTools — 모든 Action, Store 상태 및 실행 시간을 모니터링하기 위한 Redux 내장 도구입니다. 개발자는 디스패치된 모든 Action 목록, 이전과 이후의 상태 차이(diff)를 보고 이전 상태로 롤백할 수 있습니다. 이는 복잡한 상태 디버깅을 기존 로깅보다 수십 배 빠르게 만듭니다.

Redux의 핵심 구성 요소

Store — 전체 애플리케이션 상태 트리를 포함하는 객체입니다. configureStore(RTK) 또는 createStore를 통해 생성됩니다. Store는 세 가지 메서드를 제공합니다: getState()(읽기), dispatch(action)(변경), subscribe(listener)(구독). Redux Toolkit에서 Store는 이미 middleware, DevTools 및 슬라이스 지원을 포함합니다.

TypeScript
import { configureStore } from '@reduxjs/toolkit'

interface CounterState {
  value: number
}

const initialState: CounterState = { value: 0 }

function counterReducer(
  state = initialState,
  action: { type: string }
): CounterState {
  switch (action.type) {
    case 'INCREMENT':
      return { value: state.value + 1 }
    default:
      return state
  }
}

const store = configureStore({ reducer: counterReducer })
store.dispatch({ type: 'INCREMENT' })
console.log(store.getState()) // { value: 1 }

Action과 Action Creator — Action은 필수 type 필드(문자열 상수)와 선택적 payload(데이터)가 있는 객체입니다. Action Creator는 Action을 반환하는 함수입니다. Redux Toolkit에서는 자동 타입 지정으로 Action을 생성하기 위해 createAction이 사용됩니다.

Reducer — 현재 상태와 Action을 받아 새 상태를 반환하는 순수 함수입니다. Reducer는 상태를 변이해서는 안 되며(새 객체 반환), API를 호출하거나, 난수를 생성하거나, Date에 접근해서는 안 됩니다. 불변성은 spread 연산자 ... 또는 Immer(RTK에 내장)를 통해 보장됩니다.

구성 요소책임제약 사항
Store상태 저장, dispatch, subscribe애플리케이션당 하나
Action상태 변경 의도 설명type 필요
Reducer새 상태 계산순수 함수, 부작용 없음
DispatchAction을 Reducer로 전송기본적으로 동기식
SelectorStore에서 데이터 추출createSelector를 통한 메모이제이션

Middleware와 Redux Thunk

Middleware는 dispatch 호출과 Action이 Reducer에 도달하는 사이에 삽입되는 함수 체인입니다. 각 middleware는 Store API를 받아 Action을 로깅, 수정, 지연 또는 취소할 수 있습니다. Redux Thunk는 비동기 작업을 위한 표준 middleware로, 객체 대신 함수를 디스패치할 수 있게 합니다.

JavaScript
import { createAsyncThunk } from '@reduxjs/toolkit'

export const fetchUser = createAsyncThunk(
  'users/fetchById',
  async (userId: number, { rejectWithValue }) => {
    const response = await fetch(`/api/users/${userId}`)
    if (!response.ok)
      return rejectWithValue('Failed to fetch')
    return await response.json()
  }
)

인기 있는 Middleware: Redux Thunk — 간단한 비동기 호출용, Redux Saga — 생성기 사가를 사용한 복잡한 시나리오용(디바운스, 레이스, 병렬 요청), Redux Observable — 반응형 스트림을 위한 RxJS 기반. Redux Toolkit에서 middleware는 configureStoremiddleware 매개변수를 통해 연결됩니다.

State of JS 2025 설문 조사에 따르면 Thunk는 Redux 프로젝트의 72%, Saga는 18%, Observable은 5%에서 사용됩니다. 대부분의 애플리케이션에서 Thunk + RTK Query의 조합으로 비동기 데이터 워크플로우의 95%를 커버하기에 충분합니다.

Redux Toolkit과 RTK Query

Redux Toolkit(RTK)은 2019년에 출시된 Redux 로직을 작성하는 공식 권장 방법입니다. RTK에는 configureStore, createSlice, createAsyncThunkcreateEntityAdapter가 포함되어 Redux 보일러플레이트를 60-70% 줄입니다. Action Creator, Reducer 및 타입을 수동으로 생성하는 대신 단일 createSlice가 사용됩니다.

TypeScript
import { createSlice, PayloadAction } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment(state) { state.value += 1 },
    incrementByAmount(state, action: PayloadAction<number>) {
      state.value += action.payload
    }
  }
})

export const { increment, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer

RTK Query는 Redux Toolkit 기반의 API 작업을 위한 내장 솔루션입니다. createApi를 통해 엔드포인트를 선언적으로 정의할 수 있으며 자동 훅 생성, 캐싱, 태그 무효화 및 낙관적 업데이트를 제공합니다. RTK Query는 모든 API 요청에 대해 수동으로 Thunk, Reducer 및 Selector를 작성하는 것을 대체합니다.

Entity Adapter — 엔티티 컬렉션을 정규화하기 위한 createEntityAdapter 유틸리티입니다. 객체 배열에 대한 내장 CRUD 리듀서, 셀렉터 및 정렬을 제공합니다. Store에 사용자, 제품 또는 주문 목록이 포함된 경우 Entity Adapter는 리듀서 코드를 80% 줄입니다.

React Native에서 Redux

React Native Redux는 JavaScript 모바일 애플리케이션의 표준 스택입니다. Redux는 react-reduxProvider를 통해 통합되며, 루트 애플리케이션 컴포넌트를 감쌉니다. useSelectoruseDispatch 훅은 props drilling 없이 컴포넌트에 상태 접근을 제공합니다. Persistredux-persist는 Store를 AsyncStorage 또는 MMKV에 저장하여 애플리케이션 재시작 후 상태를 복원합니다.

React Native용 Middleware: Flipper를 통한 디버깅용 redux-flipper, 네이티브 드라이버를 사용한 반응형 스트림용 redux-observable, 빠른 영구 저장용 react-native-mmkv. 탐색 플러그인 redux-first-router는 화면을 Store에 연결하여 돌아올 때 화면 상태를 복원할 수 있습니다.

React Native에서 Redux는 네트워크 우선 전략과 함께 사용됩니다: 앱이 먼저 서버에서 데이터를 로드하려고 시도한 다음 RTK Query 또는 redux-persist를 통해 Store에 캐시합니다. 오프라인 모드는 Redux + NetInfo + 연결 복원 시 재전송을 위한 Action 대기열을 결합하여 구현됩니다.

자주 묻는 질문

Redux는 React의 Context API와 어떻게 다른가요?

Redux는 Store, DevTools, Middleware 및 불변 상태를 갖춘 완전한 기능의 솔루션입니다. Context API는 props drilling 없이 데이터를 전달하기 위한 React의 내장 메커니즘입니다. Context는 전역 테마 및 지역화에 적합하며, Redux는 비동기 작업, 캐싱 및 디버깅이 필요한 복잡한 상태에 적합합니다. 대규모 애플리케이션에서 Context는 불필요한 리렌더링을 유발하지만, Selector와 함께 Redux를 사용하면 이 문제가 해결됩니다.

Redux Toolkit에서 Immer란?

Immer는 Redux Toolkit에 내장된 불변 상태 관리를 위한 라이브러리입니다. Immer를 사용하면 상태를 직접 변이하는 것처럼 리듀서를 작성할 수 있습니다: state.value += 1. 내부적으로 Immer는 프록시 객체(draft)를 생성하고, 변경 사항을 추적하여 새 불변 객체를 반환합니다. 이는 리듀서 코드 양을 50% 줄이고 우발적인 변이를 제거합니다.

Redux를 테스트하는 방법은?

Redux 로직은 격리되어 테스트됩니다: Reducer — 순수 함수이므로 다른 Action으로 호출하고 결과를 확인하면 됩니다. Action Creator — 반환된 객체를 검증합니다. Thunk — API를 모킹하고, dispatch를 호출하여 어떤 Action이 디스패치되었는지 확인합니다. useSelector를 사용하는 컴포넌트 — 렌더러에서 테스트 Store와 함께 Provider를 사용합니다. Redux DevTools는 실제 세션에서 Action 시퀀스를 재생하여 테스트 작성을 돕습니다.

useState 대신 Redux를 언제 사용해야 하나요?

useState는 단일 컴포넌트의 로컬 상태에 충분합니다: 필드 텍스트, 모달 열기/닫기. Redux는 상태가 여러 화면 간에 공유되거나, 비동기 동기화(서버 데이터)가 필요하거나, 애플리케이션 재시작 간에 유지되어야 하거나(persist), 시간 여행 디버깅이 필요할 때 필요합니다. 소규모 애플리케이션에서는 Redux가 과도합니다 — 대신 Context + useReducer를 사용하세요.

Redux에서 정규화란?

Normalizr는 중첩된 데이터를 평면 Store 구조로 정규화하기 위한 라이브러리입니다. user.posts[0].comments와 같은 깊은 객체를 저장하는 대신 정규화는 사전을 생성합니다: entities.users, entities.posts, entities.comments(ID로 참조). 이는 모든 위치에서 단일 엔티티 업데이트를 간소화하고 셀렉터를 빠르게 합니다. Redux Toolkit은 복잡한 모델에 대해 정규화된 데이터를 권장합니다.

요약

  • Redux — 단일 Store와 순수 Reducer를 갖춘 예측 가능한 상태 컨테이너
  • Action — type이 있는 객체, Reducer — 순수 함수, Dispatch — 전송 메커니즘
  • Redux Toolkit — createSlice, createAsyncThunk 및 RTK Query를 갖춘 공식 API
  • Middleware — 비동기 처리를 위한 계층: Thunk, Saga, Observable
  • React Native는 Provider, useSelector 및 redux-persist를 통해 오프라인 모드로 통합
  • DevTools — 모든 Action 재생이 가능한 시간 여행 디버깅
  • Normalizr — 효율적인 셀렉터 및 업데이트를 위한 데이터 정규화

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기