본문 바로가기
코딩이야기𖦹/React

📌 복잡한 상태관리를 깔끔하게! Redux 개념 정리

by Dev디자인 2025. 4. 22.

처음엔 props로 잘 해결되지만, 규모가 커질수록 점점 어디서 상태가 바뀌는지 추적하기 어려워지는 상황이 생긴다.

이럴 때 Redux를 사용하면, 모든 상태를 한 곳(Store)에 모아서 예측 가능하게 관리할 수 있다.
Redux의 기본 개념부터 시작해서 데이터 흐름, 주요 개념,

그리고 비동기 처리까지 가능한 Redux-Thunk까지 정리 해보았다.

⚙️ Redux 설치 방법

Redux를 사용하려면 다음 두 개의 패키지를 설치해야 한다.

npm install redux react-redux

 

  • redux: 상태 관리의 핵심 기능을 제공
  • react-redux: React 앱과 Redux를 연결하는 라이브러리

⏳ 비동기 처리를 위해 Redux Thunk도 쓸 예정이라면?

npm install redux-thunk

 

설치가 완료되면, Redux를 본격적으로 사용할 준비가 완료된 것이다.

🌀 Redux란?

Redux는 앱 전체의 상태를 한 곳에서 관리할 수 있도록 해주는 라이브러리이다.
React뿐만 아니라 Vue, Angular 등과도 함께 쓸 수 있다.
가장 큰 장점은 상태를 예측 가능하게 만들고, 언제 어디서 상태가 바뀌었는지 추적하기 쉬워진다는 점이다.

📦 상태 저장소를 따로 만들고,
🗺 상태를 바꾸는 방법도 미리 정의하고,
📣 컴포넌트는 그 규칙에 따라 행동만 하도록 만든다.

🔁 Redux의 데이터 흐름 (Flux 패턴)

Redux는 데이터를 단방향으로만 흐르게 만든다.
이 구조는 Flux 패턴이라고 불리며, 흐름은 다음과 같다

  • 사용자가 UI에서 버튼 클릭 같은 동작을 하면
  • 해당 동작에 대한 Action 객체가 만들어지고
  • Dispatch 함수를 통해 전달되며
  • Reducer가 현재 상태와 Action을 바탕으로 새 상태를 계산함
  • 이 새 상태는 Store에 저장되고, 다시 UI에 반영됨

상태가 한 방향으로만 흐르기 때문에 추적이 쉽고, 버그가 적다.

🧩 Action, Dispatch, Reducer, Store의 역할

1️⃣ Action

Action은 무슨 일이 일어났는지를 나타내는 “설명서” 같은 객체다.
항상 type이라는 속성이 필요하며, 경우에 따라 추가 데이터를 담기 위한 payload 속성이 함께 사용된다.

const increment = {
  type: 'INCREMENT',
  payload: 3
}

📎 payload란?

payload는 Action을 통해 전달하고 싶은 추가 데이터다.
예를 들어, INCREMENT라는 동작을 할 때 “얼마나 증가시킬 것인지”를 payload로 전달한다.

📦 type이 택배 상자에 적힌 라벨이라면, payload는 그 안에 담긴 실제 물건이다.

2️⃣ Dispatch

dispatch()는 Action을 Reducer에게 전달하는 함수다.
쉽게 말하면, "이 액션 처리해줘!" 하고 명령을 보내는 것.

dispatch({ type: 'INCREMENT', payload: 1 })

 

Reducer는 이 액션을 받아서 새로운 상태를 계산하게 된다.

3️⃣ Reducer

Reducer는 현재 상태와 전달받은 Action을 기반으로 새로운 상태를 계산해서 반환하는 함수다.

const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + action.payload
    default:
      return state
  }
}

❗ Reducer 안에서는 상태를 직접 수정하면 안 되고, 반드시 새 값을 반환해야 한다.

 

4️⃣ Store

Store는 앱 전체의 상태를 담고 있는 중앙 저장소다.
createStore 또는 legacy_createStore를 통해 생성하며, 모든 Reducer를 하나로 묶어 전달한다.

import { legacy_createStore, combineReducers } from 'redux'

const rootReducer = combineReducers({
  counterReducer
})

const store = legacy_createStore(rootReducer)

🧷 Provider란?

Store를 만들었더라도, React 컴포넌트들이 직접 접근할 수는 없다.
이때 필요한 것이 바로 Provider이다.

Provider는 Redux의 Store를 React 앱 전체에 전달해주는 컴포넌트다.

import { Provider } from 'react-redux'

<Provider store={store}>
  <App />
</Provider>

이렇게 App을 Provider로 감싸야만, 내부 컴포넌트들에서 useSelector, useDispatch 등을 사용할 수 있게 된다.

💡 비유하자면, store가 냉장고라면 Provider는 열쇠를 모두에게 나눠주는 관리자 같은 존재다.

🛠 useDispatch()와 useSelector()란?

React 컴포넌트 안에서 Redux Store를 사용하기 위해, 우리는 두 가지 Hook을 사용한다.

🔹 useDispatch()

useDispatch()는 dispatch 함수를 꺼내오는 Hook이다.

const dispatch = useDispatch()

이 dispatch() 함수는 위에서 설명한 것처럼 액션을 리듀서로 전달하는 역할을 한다.

dispatch({ type: 'INCREMENT', payload: 2 })

 

즉, useDispatch()는 "명령을 전달할 수 있는 리모컨을 꺼내오는 함수"다.

 

🔹 useSelector()

useSelector()는 Redux Store 안에 저장된 상태 중 내가 필요한 부분만 골라서 꺼내 쓰는 Hook이다.

const count = useSelector(state => state.counterReducer)

🔍 전체 창고(Store)에서 내가 필요한 물건(상태 조각)만 집어오는 느낌이다.

⏳ Redux-Thunk란 무엇인가요?

⚠️ 먼저, “비동기”란?

비동기란 지금 바로 실행되지 않고, 나중에 실행되는 작업을 말한다.
예를 들어 API 호출(fetch, axios), setTimeout, async/await 등이 있다.

setTimeout(() => {
  console.log('3초 후 실행됨')
}, 3000)

✅ Redux-Thunk는 뭐하는 애?

Redux는 기본적으로 동기 처리만 가능하기 때문에, 위와 같은 비동기 작업을 하려면 Redux-Thunk라는 미들웨어가 필요하다.

Thunk를 사용하면 dispatch()에 단순 객체가 아닌 함수도 보낼 수 있게 된다.

const asyncIncrement = () => {
  return dispatch => {
    setTimeout(() => {
      dispatch({ type: 'INCREMENT', payload: 1 })
    }, 1000)
  }
}

 

이처럼 Thunk를 쓰면, 비동기 로직 안에서 dispatch를 자유롭게 호출할 수 있다.

import { applyMiddleware } from 'redux'
import { thunk } from 'redux-thunk'

const store = legacy_createStore(rootReducer, applyMiddleware(thunk))

✅ 마무리

 

  • Redux는 규모가 커질수록 복잡해지는 상태 관리단순하고 명확하게 만들어주는 강력한 도구이다.
  • Redux는 일방향 데이터 흐름을 가진다.
    → Action → Dispatch → Reducer → Store → UI
  • React에서는 Redux를 다음과 같은 Hook으로 손쉽게 사용할 수 있다:
    • useDispatch() : 액션을 보내기 위한 함수
    • useSelector() : Store에서 상태를 꺼내오는 함수
  • Redux를 사용하면 상태가 어디서, 어떻게 바뀌는지 추적하기 쉬워진다.
  • redux-thunk를 함께 사용하면:
    • 비동기 작업(예: API 호출, setTimeout 등)도 깔끔하게 처리할 수 있어
    • 실무에서도 매우 유용하게 활용 가능하다.

 

최근댓글

최근글

skin by © 2024 ttuttak