Redux 톺아보기⚡️
웹 애플리케이션이 점점 복잡해지면서 “상태 관리”는 프론트엔드 개발자들에게 있어 피할 수 없는 도전 과제가 되었습니다. 컴포넌트 간 데이터를 여기저기 넘기고, 앱의 상태를 이리저리 트래킹하다 보면 코드가 엉키고 디버깅도 점점 어려워지죠. 이때 Redux가 등장합니다! Redux는 대규모 애플리케이션에서도 상태를 체계적으로 관리할 수 있도록 돕는 상태 관리 라이브러리입니다.
이번 글에서는 Redux의 개념부터 작동 원리, 실제 사용 사례까지 상세히 다뤄보겠습니다. React와 궁합도 살펴보고, 실무에서 유용한 팁도 준비했으니 끝까지 읽어보세요! 😄
🌟 Redux란 무엇인가요?
Redux는 자바스크립트 애플리케이션에서 상태(state)를 예측 가능하게 관리하도록 설계된 라이브러리입니다.
Dan Abramov와 Andrew Clark가 만든 Redux는 단일 상태 트리(Single Source of Truth)를 기반으로 애플리케이션 상태를 한곳에서 관리하며, 상태 변경의 흐름을 명확히 추적할 수 있게 해줍니다.
📚 Redux의 세 가지 핵심 원칙
1. 단일 상태 트리 (Single Source of Truth)
애플리케이션의 모든 상태는 하나의 JavaScript 객체 안에 저장됩니다. 이를 **스토어(Store)**라고 부르며, 전역 상태를 관리할 수 있는 단일한 데이터 저장소입니다.
2. 상태는 읽기 전용 (State is Read-Only)
상태는 직접 수정할 수 없으며, 상태를 변경하려면 반드시 **액션(Action)**을 통해야 합니다. 이를 통해 상태 변경 과정을 명확히 추적할 수 있습니다.
3. 순수 함수로 상태 변경 (Changes are Made with Pure Functions)
상태 변경은 항상 순수 함수인 **리듀서(Reducer)**를 통해 이루어집니다. 동일한 입력이 주어지면 항상 동일한 결과를 반환해야 하며, 외부 상태를 변경하지 않습니다.
🧮 Redux의 작동 원리
Redux는 다음과 같은 흐름으로 작동합니다:
1. Action (액션)
애플리케이션에서 발생한 이벤트를 설명하는 객체입니다. 예를 들어, “장바구니에 상품 추가”라는 액션은 type 속성과 함께 추가 데이터를 포함할 수 있습니다.
const addItemToCart = (item) => {
return {
type: 'ADD_ITEM',
payload: item,
};
};
2. Reducer (리듀서)
액션을 기반으로 새로운 상태를 반환하는 순수 함수입니다. 현재 상태와 액션 객체를 입력으로 받아 새 상태를 반환합니다.
const cartReducer = (state = [], action) => {
switch (action.type) {
case 'ADD_ITEM':
return [...state, action.payload];
default:
return state;
}
};
3. Store (스토어)
애플리케이션의 상태를 보관하는 저장소입니다. 스토어는 createStore 함수로 생성하며, 리듀서를 포함합니다.
import { createStore } from 'redux';
const store = createStore(cartReducer);
4. Dispatch (디스패치)
스토어에 액션을 전달하는 메서드입니다. 디스패치는 액션을 리듀서로 보내 상태를 업데이트합니다.
store.dispatch(addItemToCart({ id: 1, name: 'React Book' }));
5. Subscription (구독)
상태가 변경될 때마다 특정 로직을 실행할 수 있습니다. store.subscribe를 사용해 상태 변화를 감지합니다.
store.subscribe(() => {
console.log('State updated:', store.getState());
});
🚁 Redux와 React의 연결
React는 Redux와 함께 사용하기 위해 react-redux 라이브러리를 제공합니다. 이 라이브러리는 Redux 스토어를 React 컴포넌트에 쉽게 연결할 수 있도록 도와줍니다.
1. Provider 컴포넌트
Provider는 React 컴포넌트 트리 전체에 Redux 스토어를 제공합니다.
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import cartReducer from './reducers';
const store = createStore(cartReducer);
function App() {
return (
<Provider store={store}>
<ShoppingCart />
</Provider>
);
}
2. useSelector와 useDispatch
React Redux의 훅을 사용해 상태를 가져오거나 액션을 디스패치할 수 있습니다.
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
function ShoppingCart() {
const cart = useSelector((state) => state);
const dispatch = useDispatch();
const addItem = () => {
dispatch({ type: 'ADD_ITEM', payload: { id: 2, name: 'Redux Guide' } });
};
return (
<div>
<h2>Shopping Cart</h2>
<ul>
{cart.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
<button onClick={addItem}>Add Item</button>
</div>
);
}
⛲️ 실전에서 Redux를 사용해야 할 때
- 글로벌 상태 관리가 필요한 경우
- 사용자 인증 정보
- 테마, 언어 설정
- 쇼핑카트 상태
- 컴포넌트 간 데이터 전달이 복잡할 때
- 중첩된 컴포넌트 트리에서 데이터를 주고받아야 하는 상황
- 상태 변경 로직을 명확히 추적해야 할 때
- Redux의 액션과 리듀서를 사용하면 상태 변경 과정을 철저히 기록할 수 있습니다.
⚠️ Redux 사용 시 주의할 점
- 복잡성 증가
- 작은 프로젝트에서는 Redux가 오히려 코드 복잡성을 높일 수 있습니다. 상태 관리가 단순하다면 Context API나 React 훅으로 충분할 수 있습니다.
- 보일러플레이트 코드
- 액션, 리듀서, 스토어 설정 등 초기 설정에 많은 코드가 필요합니다. 이를 줄이기 위해 Redux Toolkit 같은 도구를 사용하는 것이 좋습니다.
- 성능 최적화 필요
- 상태 변경 시 불필요한 렌더링을 방지하려면 React.memo와 같은 최적화 기법을 활용하세요.
📋 Redux의 대안: Context API와 비교
기능 | Redux | Context API |
상태 관리 규모 | 대규모 애플리케이션 | 중소규모 애플리케이션 |
의존성 | 외부 라이브러리 필요 | React 내장 기능 |
유연성 | 다양한 미들웨어와 강력한 상태 관리 | 단순한 상태 관리에 적합 |
보일러플레이트 | 많음 | 적음 |
📑 Redux 사용의 요약
Redux는 글로벌 상태 관리의 강력한 도구로, 상태 변경 과정을 명확히 하고, 복잡한 애플리케이션에서도 상태를 깔끔하게 유지할 수 있게 해줍니다. 하지만 모든 프로젝트에 Redux가 필요한 것은 아니므로, 프로젝트 규모와 상태 관리 요구 사항에 따라 적절히 선택하세요.
🌷 전설의 개발자가 되어봅시당! 🌷
'Front-end > React' 카테고리의 다른 글
[React] Redux Thunk: 미들웨어의 맛깔나는 조미료 🍲 (0) | 2025.01.07 |
---|---|
[React] React Query: 데이터를 사랑하는 리액트 개발자의 필수템 💖 (0) | 2025.01.06 |
[React] Context: 글로벌 상태 관리의 은밀한 해결사 🌍 (0) | 2024.12.31 |
[React] Flux: React의 단방향 테이터 아키텍쳐! 🔄 (0) | 2024.12.29 |
[React] Diff Algorithm: 변화 감지의 마법을 알아보자! 🔍 (0) | 2024.12.27 |