현재 오즈코딩스쿨 강의를 통해 프론트엔드를 학습하고 있습니다.
본 포스트는 해당 강의에 대한 내용 정리를 목적으로 합니다.

Redux는 자바스크립트 애플리케이션의 상태(state)를 효율적으로 관리하기 위한 상태 관리 라이브러리이다.
npm install redux react-reduxRedux는 Flux 아키텍처를 기반으로 한 구조를 따르며, 데이터가 단방향으로 흐른다.

View(UI)에서 사용자 행동 → Action을 생성하고 → Dispatch로 Action을 전달하면 →
Reducer가 현재 상태와 Action을 바탕으로 새 상태를 계산 → Store가 새로운 상태를 보관 →
View는 상태 변경을 감지하고 리렌더링
즉, "Action → Dispatch → Reducer → Store → View"의 순환 구조이다.
상태를 어떻게 변화시킬 것인지에 대한 내용이 담겨있는 객체.
const incrementAction = {
type: 'INCREMENT',
};
const addTodoAction = {
type: 'ADD_TODO',
payload: {
id: 1,
text: 'Redux 공부하기',
},
};
const increment = () => {
return {
type: 'INCREMENT',
};
};
const addTodo = (id, text) => {
return {
type: 'ADD_TODO',
payload: {
id,
text,
},
};
};
액션 객체를 Reducer로 넘겨주는 역할을 하는 함수
// 액션 객체
const incrementAction = {
type: 'INCREMENT',
};
// Dispatch로 전달
dispatch(incrementAction);
위 예시는 INCREMENT 타입의 액션 객체를 직접 만들어 dispatch에 전달하는 방식이다.
// 액션 생성자
const increment = () => {
return {
type: 'INCREMENT',
};
};
// Dispatch로 전달
dispatch(increment());
위 예시는 increment()라는 액션 생성자를 통해 액션 객체를 생성하고, 그것을 dispatch에 전달하는 방식이다.
리턴하는 값이 새로운 상태가 되는 함수
const reducer = (state = 초기값, action) => {
switch (action.type) {
case '액션타입':
return 새로운_상태;
default:
return state;
}
};
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
};
이 Reducer는 숫자 상태를 관리하며, INCREMENT 액션이 오면 +1, DECREMENT가 오면 -1을 반환하는 구조이다.
✅ Reducer의 특징
combineReducers()를 통해 하나로 합칠 수 있다.✅combineReducers() 예시
import { combineReducers } from 'redux';
// 카운터 상태를 처리하는 리듀서
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
};
// 로그인 상태를 처리하는 리듀서
const authReducer = (state = { isLoggedIn: false }, action) => {
switch (action.type) {
case 'LOGIN':
return { isLoggedIn: true };
case 'LOGOUT':
return { isLoggedIn: false };
default:
return state;
}
};
// 두 reducer를 결합
const rootReducer = combineReducers({
counter: counterReducer,
auth: authReducer,
});
위 예시에서 combineReducers()는 counter와 auth라는 상태 조각을 각각 담당하는 reducer들을 하나로 합쳐 rootReducer로 만든 것이다.
{
counter: 0,
auth: {
isLoggedIn: false
}
}
이 경우 Redux store의 전체 상태는 다음과 같이 구성된다.
Redux의 전역 상태 저장소, createStore 함수에 Reducer를 전달해서 생성
import { createStore } from 'redux';
// 간단한 reducer
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
};
// store 생성
const store = createStore(counterReducer);
// 상태 조회
console.log(store.getState()); // 0
// 액션 디스패치
store.dispatch({ type: 'INCREMENT' });
// 상태 다시 조회
console.log(store.getState()); // 1

컴포넌트에서 Action을 발생시키기 위한 함수를 제공
const dispatch = useDispatch();
dispatch({ type: 'INCREMENT' });
Store 안의 상태를 읽어오기 위한 함수
const count = useSelector((state) => state);
Redux-Thunk는 비동기 작업을 처리하기 위한 미들웨어이다.
// 비동기 액션 생성 함수
const fetchData = () => {
return async (dispatch) => {
dispatch({ type: 'LOADING' });
const res = await fetch('/api/data');
const data = await res.json();
dispatch({ type: 'SUCCESS', payload: data });
};
};
Thunk는 redux-thunk 패키지를 설치하고 applyMiddleware()로 store에 연결해서 사용한다.
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
const store = createStore(reducer, applyMiddleware(thunk));
npm install redux-thunk
Redux Toolkit은 Redux 공식 팀에서 제공하는 상태 관리 툴킷으로, 복잡하고 반복적인 Redux 코드를 더 간결하고 직관적으로 작성할 수 있도록 도와주는 라이브러리이다.
Redux의 표준 방식으로 권장되며, createSlice, configureStore, createAsyncThunk 등의 API를 제공한다.
즉, Redux Toolkit은 Redux 개발을 쉽게 만들어주는 도구 모음이다.
npm install @reduxjs/toolkit react-redux
| 구분 | Redux | Redux Toolkit |
|---|---|---|
| 액션 정의 | 수동 작성 | createSlice()로 자동 생성 |
| 리듀서 작성 | 직접 작성 | createSlice()로 간단히 정의 |
| 상태 변경 | 불변성 수동 처리 | Immer 내장으로 직관적인 코드 작성 가능 |
| 비동기 처리 | Thunk 등 수동 설정 | createAsyncThunk() 제공 |
| 개발자 도구 | 별도 설정 필요 | configureStore()로 자동 연동 |
createSlice()는 state, reducer, action creator를 한 번에 정의하는 함수이다.
이 함수로 상태 로직을 모듈 단위로 구성할 수 있다.


// counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: {
increment: (state) => state + 1,
decrement: (state) => state - 1,
}
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
정리하면, createSlice()는 상태값과 관련된 모든 것을 하나로 묶어서 정의할 수 있는 함수이다.
configureStore()는 Redux의 createStore()를 대체하는 함수이며,
reducer 설정, Redux DevTools 연동, 미들웨어 설정 등을 쉽게 할 수 있도록 도와준다.

// store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export const store = configureStore({
reducer: counterReducer
});
정리하면, configureStore()는 Redux의 스토어를 더 쉽게 생성하고 설정해주는 함수이다.
비동기 처리를 위해 Redux Toolkit에서는 createAsyncThunk()를 사용한다.
이 함수는 API 요청과 같은 비동기 작업을 액션처럼 정의할 수 있게 해준다.
createAsyncThunk()는 비동기 요청에 대해 pending, fulfilled, rejected의 세 가지 상태를 자동으로 생성해주는 함수이다.
// 예시: 비동기 사용자 정보 가져오기
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
// Thunk 정의
export const fetchUser = createAsyncThunk(
'user/fetchUser',
async (userId) => {
const response = await fetch(`/api/user/${userId}`);
return await response.json();
}
);
// Slice 정의
const userSlice = createSlice({
name: 'user',
initialState: { data: null, status: 'idle' },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.data = action.payload;
state.status = 'succeeded';
})
.addCase(fetchUser.rejected, (state) => {
state.status = 'failed';
});
}
});
정리하면, createAsyncThunk()는 비동기 로직을 Redux 액션처럼 작성할 수 있게 해주는 도구이며,
자동으로 처리 상태를 관리할 수 있도록 도와주는 함수이다.