
Redux는 JavaScript 애플리케이션에서 상태(state) 관리를 효율적으로 할 수 있도록 도와주는 라이브러리이다.
특히 React와 함께 많이 사용되며, 대규모 애플리케이션에서 상태를 일관성 있게 관리하는 데 유용하다.
Redux는 Flux 아키텍처에서 영감을 받아 만들어졌으며, 애플리케이션의 상태를 예측 가능하고, 중앙에서 한눈에 파악할 수 있도록 한다!
React에서는 기본적으로 컴포넌트 간 상태를 공유할 때 props를 사용하여 데이터를 전달한다.
하지만 애플리케이션이 커지면서 여러 컴포넌트가 동일한 데이터를 공유해야 할 경우, 상태 관리가 복잡해진다.
예를 들어, 부모-자식 관계가 깊어질수록 props를 통해 데이터를 전달하는 것이 번거로워지고, 형제 컴포넌트 간 상태 공유가 어려워진다.
또한, 전역적인 상태 관리가 필요할 경우, 여러 개의 useState와 useContext를 사용하는 것이 불편할 수 있다.
🫠 상태 관리의 어려움
- 컴포넌트 트리가 깊어질수록 props 전달이 복잡해짐 → props drilling 문제 발생
- 형제 컴포넌트 간 상태 공유 어려움 → 전역 상태 관리 필요
- 비효율적인 상태 업데이트 → 여러 컴포넌트에서 동일한 상태를 사용하면 비효율적인 렌더링 발생 가능
- 비즈니스 로직이 여러 컴포넌트에 분산됨 → 코드가 복잡해지고 유지보수 어려움
이때 Redux를 사용하면 중앙에서 상태를 관리할 수 있어 코드의 유지보수성과 가독성이 높아지며, 상태의 흐름을 예측하기 쉬워진다!
Redux는 세 가지 핵심 개념을 기반으로 작동한다
- 📦 Store (스토어)
- 애플리케이션의 모든 상태를 저장하는 단일 저장소이다.
- 스토어는 하나만 존재하며, 애플리케이션의 중앙에서 상태를 관리한다.
- ⚡ Action (액션)
- 상태를 변경하는 유일한 방법으로, 어떤 동작을 할지 정의하는 객체이다.
- 🔁 Reducer (리듀서)
- 현재 상태와 액션을 받아 새로운 상태를 반환하는 순수 함수이다.
- 상태(state)는 직접 수정하는 것이 아니라, 기존 상태를 복사하여 새로운 상태를 반환한다.
사용자가 특정 이벤트를 발생시킴 (예: 버튼 클릭)
해당 이벤트에 대한 액션(Action) 객체가 생성됨
생성된 액션이 dispatch를 통해 스토어(Store)에 전달됨
스토어는 리듀서(Reducer)를 호출하여 새로운 상태를 계산함
스토어가 상태를 업데이트하면, 상태를 구독하고 있는 컴포넌트가 리렌더링됨
컴포넌트 → 액션 → 디스패치 → 리듀서 → 스토어 → 새로운 상태 업데이트 → 컴포넌트 리렌더링
1️⃣Redux 설치
Redux와 React에서 사용하기 위한 react-redux 라이브러리를 설치한다.
npm install redux react-redux
2️⃣Redux 기본 코드 구조
1. 액션(Action) 정의
// actions.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const increment = () => ({ type: INCREMENT });
export const decrement = () => ({ type: DECREMENT });
2. 리듀서(Reducer) 생성
// reducer.js
import { INCREMENT, DECREMENT } from './actions';
const initialState = {
count: 0
};
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 };
case DECREMENT:
return { count: state.count - 1 };
default:
return state;
}
};
export default counterReducer;
3. 스토어 (Store)생성
// store.js
import { createStore } from 'redux';
import counterReducer from './reducer';
const store = createStore(counterReducer);
export default store;
// App.js
import React from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store from './store';
import { increment, decrement } from './actions';
const Counter = () => {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
);
};
const App = () => (
<Provider store={store}>
<Counter />
</Provider>
);
export default App;
👍🏻장점
전역 상태 관리 → 모든 상태를 한 곳에서 관리할 수 있다.
예측 가능한 상태 변경 → 상태 변경 로직이 명확하여 디버깅이 용이하다.
Redux DevTools 지원 → 상태 변경을 시각적으로 확인 가능하다.
컴포넌트 간 상태 공유가 간편함 → props 전달 없이 여러 컴포넌트에서 동일한 상태를 사용할 수 있다.
👎🏻단점
코드의 복잡성이 증가할 수 있다.
보일러플레이트 코드(반복적인 코드)가 많다.
작은 프로젝트에서는 오버헤드가 발생할 가능성이 있다.
이번 프로젝트를 진행하면서 Redux를 처음 사용해보았다. 처음에는 상태 관리의 개념이 생소하고 복잡하게 느껴졌지만, 직접 적용하면서 Redux의 장점을 체감할 수 있었다.
특히, 여러 컴포넌트에서 동일한 상태를 공유해야 할 때 props를 깊이 전달하는 불편함 없이 전역에서 상태를 관리할 수 있다는 점이 가장 인상적이었다.
또한, 상태의 흐름이 명확하게 관리되면서 특정 액션이 발생할 때 어떤 변화가 일어나는지 예측하기 쉬웠다.
Redux DevTools을 활용하여 상태 변화 과정을 시각적으로 확인할 수 있어 디버깅이 편리했다.
물론, 작은 프로젝트에서는 Redux가 불필요할 수도 있지만, 복잡한 상태 관리가 필요한 프로젝트에서는 필수적인 도구라고 느꼈다.
Redux는 대규모 애플리케이션에서 강력한 상태 관리 기능을 제공하지만, 모든 프로젝트에 필수적인 것은 아니다.
상태 관리가 비교적 단순한 프로젝트에서는 useState나 useContext를 사용하는 것이 더 적절할 수 있을 것 같다!