[React] 전역 상태 관리 (3) - Redux

박하늘·2025년 2월 27일

React

목록 보기
11/15
post-thumbnail

Redux 란?

  • 가장 대표적이고 근본인 전역 상태 관리 라이브러리
  • 상태 관리 라이브러리 중 가장 많이 사용 되고 있음
  • 예측 가능한 상태 관리(Predictable State Management) 를 목표로 하며, 애플리케이션의 상태를 한 곳에서 관리하고, 상태 변경이 일어나는 흐름을 명확하게 만들기 위해 사용됩니다.

⚙️ 기본 설치

터미널에 입력 ... ✍🏻

npm i redux
npm i react-redux

Redux의 데이터 흐름

[FLUX 패턴]
UI, Action, Dispatch, Reducer, Store 5가지가 redux의 구성요소

1️⃣ UI

  • 사용자가 직접 상호작용하는 화면 요소이며, 상태(state)를 기반으로 렌더링
  • UI에서 특정 이벤트가 발생하면 Action을 생성하여 Redux 스토어에 상태 변경을 요청할 수 있습니다.

2️⃣ Action

  • 애플리케이션에서 상태(state)를 변경하는 유일한 방법으로, 어떤 변화가 필요한지 설명하는 객체입니다.
  • type 속성을 필수적으로 가지고 있으며, 추가적인 데이터를 payload전달할 수도 있습니다.
  • UI에서 버튼 클릭 등의 이벤트가 발생하면 특정 액션이 생성됩니다.
//📍 액션 객체(Action Object) 방식

{ type: "INCREMENT", payload: 1 }
{ type: "DECREMENT", payload: 1 }

//📍✨ 액션 생성자(Action Creator) 방식
// 객체를 때마다 만들기 번거롭다 느껴지면 액션 객체를 반환시키는 함수를 사용한다
//payload 값을 동적으로 설정 가능
// payload : 특정한 값을 이용하여 상태를 변경 시키겠다

const incrementAction = {
  type: "INCREMENT",
  payload: { id }
};

3️⃣ Dispatch

  • dispatch(action)을 사용하여 Action을 Reducer에게 전달하는 역할
  • UI나 기타 비즈니스 로직에서 dispatch를 호출하여 스토어에 상태 변경을 요청
  • dispatch를 호출하면 Redux는 해당 액션을 Reducer로 보냄
//📍 액션 객체(Action Object) 방식

dispatch({
	type: 'INCREMENT'
	payload: 5
})

//📍✨ 액션 생성자(Action Creator) 방식

dispatch( increment ( 5 ) )
액션 생성자

4️⃣ Reducer

  • Action을 받아 현재 상태를 기반으로 새로운 상태를 반환하는 순수 함수
  • 기존 상태를 직접 변경하는 것이 아니라, 변경된 새로운 상태 객체를 반환해야 함 → state상태값 / action리듀서로 부터 전달받는 값
// state에 설정해주는 초기 값이 상태 저장소를 만들었을 떄 그 상태의 초기값
const counterReducer = (state = { count: 0 }, action) => {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + action.payload };
    case "DECREMENT":
      return { count: state.count - action.payload };
    default:
      return state;
      // 이상한 값이 들어오면 리턴을 받지 못하여 undefind 가 나오기 때문에 기본값을 유지하는 default 값도 작성 필요
  }
};

// 🔮 Reducer가 여러 개라면?
// combineReducers 함수로 묶어서 하나로 만들 수 있음

const rootReducer = combineReducers({
counterReducer, anyReducer, ...
})

5️⃣ Store

  • Redux의 전역 상태 저장소
  • createStore 함수에 Reducer를 전달해서 생성
const store = createStore( rootReducer )
// createStore 가 프로그램에서 취소선으로 막혀 있을 때 legacy_createStore 이걸로 사용하여도 무방

6️⃣ 구성 요소를 다 만들었다면?
React-Redux에서 제공하는 기능을 사용해서

✔️ App과 전역 상태 저장소 연결하기 <Provider store={ store } >

📁 main.jsx

import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import { store } from './redux/redux.js'

ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<Provider store={store}>
      <App />
</Provider>
</BrowserRouter>,
)

✔️ 상태 저장소에서 상태 꺼내서 사용하기 useSelector( )

  • useSelector((state) => state.reducer명)을 사용하여 Redux의 state를 직접 가져올 수 있습니다.
import { useSelector } from "react-redux";

const CounterDisplay = () => {
  // 상태에서 count 값 가져오기
  const count = useSelector((state) => state.countReducer);

  return <h1>Count: {count}</h1>;
};

✔️ dispatch 함수 만들어서 사용하기 useDispatch( )

  • Redux의 액션을 디스패치할 때 사용합니다.
  • dispatch(action)을 호출하여 Reducer에 액션을 전달할 수 있습니다.
import { useDispatch } from "react-redux";

const CounterButton = () => {
  const dispatch = useDispatch();

  return (
    <button onClick={() => dispatch(INCREMENT)}>
      증가하기
    </button>
  );
};



Redux-Thunk

  • Redux에서 비동기 처리를 할 수 있게 해주는 미들웨어
  • dispatch()가 액션 객체뿐만 아니라, 함수를 전달할 수 있도록 확장

⚙️ 설치

npm i redux react-redux
npm i redux-thunk

1️⃣ store 설정

  • Redux에서 Store 지정해준 곳에 추가 인자로 applyMiddleware를 사용하여 thunk 미들웨어를 적용해야 합니다.
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers"; // 리듀서

const store = createStore(rootReducer, applyMiddleware(thunk));

export default store;

2️⃣ 사용하기

  • 객체(INCREMENT) 만 넣어주는 대신 함수를 사용할 수 있다
  • dispatch((dispatch) => {} ) 공식으로 외우면 됨
import { useDispatch } from "react-redux";

const CounterButton = () => {
  const dispatch = useDispatch();

  return (
    <button onClick={() => dispatch((dispatch) => {
        setTimeout(() => {
          dispatch(INCREMENT)
        }, 1000)
        )}>
      증가하기
    </button>
  );
};



⚛️ Redux 사용 예제 (기본 코드)

import { createStore } from "redux";

// 1️⃣ 액션 생성
const INCREMENT = "INCREMENT";
const incrementAction = { type: INCREMENT };

// 2️⃣ 리듀서 함수 정의
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case INCREMENT:
      return state + 1;
    default:
      return state;
  }
};

// 3️⃣ 스토어 생성
const store = createStore(counterReducer);

// 4️⃣ 상태 변경 감지
store.subscribe(() => console.log("현재 상태:", store.getState()));

// 5️⃣ 액션 디스패치
store.dispatch(incrementAction); // 현재 상태: 1
store.dispatch(incrementAction); // 현재 상태: 2



⚛️ Redux의 주요 특징

  • 단일 스토어 (Single Source of Truth)
    모든 상태가 하나의 스토어에 저장되므로 상태 관리가 쉬워집니다.

  • 불변성 (Immutability)
    상태는 직접 변경할 수 없으며, 새로운 상태 객체를 만들어 교체합니다.

  • 예측 가능성 (Predictability)
    상태 변화가 액션을 통해서만 이루어지므로 디버깅이 쉽습니다.

  • 미들웨어 지원 (Middleware)
    Redux Thunk, Redux Saga 같은 미들웨어를 사용하면 비동기 작업도 쉽게 처리할 수 있습니다.

0개의 댓글