처음엔 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 등)도 깔끔하게 처리할 수 있어
- 실무에서도 매우 유용하게 활용 가능하다.
'코딩이야기𖦹 > React' 카테고리의 다른 글
📌 React 성능 최적화 정리 (1) | 2025.04.24 |
---|---|
📌 React 렌더링 최적화: memo, useMemo, useCallback 완전정복하기 (0) | 2025.04.23 |
📌 Context API로 전역 상태 관리 하기 (0) | 2025.04.21 |
📌 React 앱을 가볍게! 전역 상태 관리로 구조 최적화하기 (0) | 2025.04.18 |
📌 Tailwind CSS 진짜 편한가? (0) | 2025.04.17 |