리덕스를 사용하다 보면, 느끼는 것이 있습니다.
- 잘 사용하기 위해서는 너무 복잡한 구성을 필요로 합니다.
- 복잡한 구성 만큼이나 많은 미들웨어와 추가적인 패키지를 설치해야 됩니다.
- 보일러플레이트 코드가 과도하게 많이 사용 됩니다.
위 문제점을 toolkit이 완전하게 해결 하지는 못하지만, redux를 사용하는 사용자들의 불편을 완화 시켜 준다고 합니다.
줄여서 RSK 라고 부릅니다.
설치
yarn add @reduxjs/toolkit
or
npm install @reduxjs/toolkit
toolkit에 포함된 도구들
- configureStore() :
createStore
를 통한 복잡한 설정을 단순화 하고, redux devtools 설정을 추가 해주었습니다. - createReducer() : switch 문을 작성하지 않고, case reduce 처리. state의 불변 업데이트 지원.
- createAction() : Flux standard action 지원
- createSlice() : duck 패턴 지원
- createSelector : Reselector 지원
configStore
store를 생성하고 미들웨어를 추가하는 부가적인 작업들이 아래와 같이 간단하게 변경 되었습니다.
const store = configureStore({
reducer: rootReducer,
middleware: [thunk, logger],
})
createSlice
createReducer
& createAction
기능을 통합하여 createSlice
라는 것이 생겼습니다.
더 자세히 알고 싶으시다면, ducks패턴 에 대해서 알아 보시면 됩니다.
import { createSlice } from '@reduxjs/toolkit'
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
addTodo(state, action) {
const { id, text } = action.payload
state.push({ id, text, completed: false })
},
toggleTodo(state, action) {
const todo = state.find(todo => todo.id === action.payload)
if (todo) {
todo.completed = !todo.completed
}
}
}
})
export const { addTodo, toggleTodo } = todosSlice.actions
export default todosSlice.reducer
구문
createSlice
는 옵션과 함께 옵션 객체를 인수로 사용합니다.
- name: 생성 된 조치 유형의 접 두부로 사용되는 문자열
- initialState : Reducer의 초기 상태 값
- reducers : 초기 문자열이 키가 되며, 이후 함수는 실행될 내용입니다. (case reducers)
불필요한 'default' 처리
default
처리가 필요 없습니다. createSlice
는 현재 상태를 반환하여 주므로 switch
문을 사용하던 것과 같이 default
를 나열하지 않아도 됩니다.
immutable로 부터 해방
state
는 불편 하게 처리 하여야 되기 때문에 수정이 불가능 하였습니다. RSK는 createReducer
, createSlice
의 API의 내부적 처리를 대신 해주기 때문에 mutable한 state 객체를 주게 됩니다.
createAction
redux-actions 에서 지원하는 API중 createAction
를 동일한 이름 을 지원 합니다.
const INCREMENT = 'INCREMENT'
const DECREMENT = 'DECREMENT'
function increment() {
return { type: INCREMENT }
}
function decrement() {
return { type: DECREMENT }
}
function counter(state = 0, action) {
switch (action.type) {
case INCREMENT:
return state + 1
case DECREMENT:
return state - 1
default:
return state
}
}
const store = Redux.createStore(counter)
document.getElementById('increment').addEventListener('click', () => {
store.dispatch(increment())
})
위 구문이 createAction
를 사용하면 아래 구문이 됩니다.
const increment = createAction('INCREMENT')
const decrement = createAction('DECREMENT')
function counter(state = 0, action) {
switch (action.type) {
case increment.type:
return state + 1
case decrement.type:
return state - 1
default:
return state
}
}
const store = Redux.createStore(counter)
document.getElementById('increment').addEventListener('click', () => {
store.dispatch(increment())
})
payload
FSA(Flux Standard Actions) 규약은 임의의 이름을 가진 데이터 필드를 직접 가지지 않고, payload
라는 이름을 가진 객체에 데이터 필드를 가져야 된다고 제안 합니다.
즉, {type, id, password}가 있다면, id와 password를 payload에 넣어 {type, payload}로 구성 한다는 것입니다.
interface Action<Payload> extends AnyAction {
type: string
payload: Payload
error?: boolean
meta?: Meta
}
createReducer
action과 reducer를 연결해주는 역할을 하며, redux-actions에서는 handleAction 이라는 API로 지원 되었습니다. 이를 createReducer라는 이름으로 지원 합니다.
import { createAction, createReducer } from 'redux-toolkit'
const increment = createAction('INCREMENT')
const decrement = createAction('DECREMENT')
const counter = createReducer(0, {
[increment.type]: state => state + 1,
[decrement.type]: state => state - 1,
})
const store = configureStore({
reducer: counter,
})
또, createSlice 와 동일하게, immutable 관련 문제를 지원 합니다.
createSelector
Reselector API를 통해 사용하던 selector 기능 입니다. store에 어떤 값에 반복 접근할때 memorization을 통해 성능을 향상 시키게 됩니다. Vue진영에서는 Vuex getter, MobX는 computed로 기본 적으로 제공 되던 기능인듯 합니다.
import { createSelector } from '@reduxjs/toolkit'
const selectTodos = state => state.todos
const selectFilter = state => state.visibilityFilter
const selectVisibleTodos = createSelector(
[selectTodos, selectFilter],
(todos, filter) => {
switch (filter) {
case VisibilityFilters.SHOW_ALL:
return todos
case VisibilityFilters.SHOW_COMPLETED:
return todos.filter(t => t.completed)
case VisibilityFilters.SHOW_ACTIVE:
return todos.filter(t => !t.completed)
default:
throw new Error('Unknown filter: ' + filter)
}
}
prefix가 get
보다 select
를 권장한다고 합니다.
'React.js' 카테고리의 다른 글
WebStorm 에서 prettier / ESLint 사용하기 (0) | 2020.02.15 |
---|