Redux-toolkit을 사용해보자
분명 배운 지 며칠 안됐는데 벌써 가물가물해서 기본 개념부터 다시 짚으면서 써 봐야겠다.
(복습) Redux란?
전역 상태관리 라이브러리로서 React App 내의 수많은 컴포넌트들에 분산되어 있는 수많은 상태들을 한데 모아 관리할 수 있도록 해주는 역할.
작동 원리같은 거 고려 안하고 Redux의 개념을 직관적으로 가장 잘 보여주는 그림 되시겠다
그래서 Redux를 쓸 때 핵심적으로 봐야 하는 요소가 무엇무엇이 있었냐면: "Single Source of Truth" 전역 상태를 저장하는 Store이 존재하고, 그 Store의 Variable을 바꾸는 방법은 Reducer로 미리 정의되어 있어야 하며 데이터의 흐름을 단일 방향이어야 한다.
여기까지만 보면 참 좋은데...
Redux의 문제점
하나의 Action을 만들고 싶다면?
Action 타입 정의 및 함수 생성 -> Reducer 정의 가 필요하다.
간단한 Counter을 하나 만들어보도록 하자. (출처: devSoo님의 블로그)
CreateAction
const INCREMENT = 'counter/increment'
function increment(amount) {
return {
type: INCREMENT,
payload: amount
}
}
const action = increment(3)
// { type: 'counter/increment', payload: 3 }
CreateReducer
function counterReducer(state = 0, action) {
switch (action.type) {
case 'increment':
return state + action.payload
case 'decrement':
return state - action.payload
default:
return state
}
}
ConfigureStore
import { createStore } from "redux";
import rootReducer from "./Redux/Reducer";
const devTools = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__();
const store = createStore(rootReducer, devTools);
increment action 하나를 위해서 지금 여러 줄의 코드가 작성되었다.
더 복잡해 보이라고 createSlice 안썼다
Redux-toolkit 등장⭐️
CreateAction 진화버전
const increment = createAction('counter/increment')
let action = increment() ✅ 사용
// { type: 'counter/increment' }
action = increment(3) ✅ 사용
// returns { type: 'counter/increment', payload: 3 }
CreateReducer 진화버전
const counterReducer = createReducer(0, {
increment: (state, action) => state + action.payload,
decrement: (state, action) => state - action.payload
})
ConfigureStore 진화버전
import { configureStore } from '@reduxjs/toolkit';
export const store = configureStore({
reducer: {
counter: counterReducer,
todos: todosReducer,
},
});
딱 봐도 양이 짧아졌고, Default가 기본으로 지정되어 있으며 configureStore을 보면 reducer 필드 안에 그냥 만든 녀석들을 박아넣기만 하면 알아서 작동한다.
Ducks Pattern?
Redux-toolkit을 사용하면서 준수하는 디자인 패턴이다. 디자인 패턴과 개발 컨벤션의 차이에 대해서는 많이 들었을 테니까 넘어가고, 그렇다면 어떻게 디자인해야 바람직한가? 이에 대한 해답은 규칙 하나와 그림 하나로 대신하는 게 좋다.
MUST export default a function called reducer()
MUST export its action creators as functions
MUST have action types in the form npm-module-or-app/reducer/ACTION_TYPE
MAY export its action types as UPPER_SNAKE_CASE, if an external reducer needs to listen for them, or if it is a published reusable library
뻔해 보이는 규칙이지만 지켰을 때 코드의 가독성과 단순성, 구조를 향상시킬 수 있는 규칙이다.
"하나의 상태에 필요한 액션 타입, 생성사 함수, 리듀서를 한 파일에 저장한다" -> 이를 통해 한 액션을 추가할 때마다 딱 하나의 파일이 늘어나는 구조를 완성시킨다.