createSlice는 생성된 reducer함수를 reducer라는 필드를 포함하는 "slice"객체와 actions이라는 객체 내부에서 생성된 액션 생성함수를 반환한다.
리덕스 모듈 하나를 만들기 위해서는 action type을 정의하고, actionCreator를 만들고 Reducer까지 만들어야 하는데 createSlice로 한번에 다 해결이 가능하다.
createSlice는 다음 옵션과 함께 option 객체를 인자로 사용한다.
name: createAction types를 생성하기 위해 사용되는 prefix
initialState : reducer의 초기 상태
reducer: key는 action type문자열이 되고, 메소드는 해당 액션이 dispatch 될 때 실행 될 reducer이다.
createSlice에 의해 생성된 리듀서는 현재 dispatch된 액션이 아닌 다른 액션에 의해 자동으로 현재 상태를 반환하도록 처리되어 있기에, 직접 핸들링 하지 않아도 된다.
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: {
increment: state => state + 1,
decrement: state => state - 1
}
})
const store = configureStore({
reducer: counterSlice.reducer
})
document.getElementById('increment').addEventListener('click', () => {
store.dispatch(counterSlice.actions.increment())
})
export const { increment } = slice.action;
export default todoSlice.reducer
일반적으로 Redux에서는 절대적으로 불변성(immutable)을 지키며 코드를 짜야 한다.
array.push() 같은 식으로 state를 직접 변경하는 방법은 좋지 않다.
그러나 @redux/tool-kit의 createSlice
와 createReducer
는 Immer 라이브러리의 produce로 래핑한다. 이로 인해 개발자는 내부의 상태를 변형하는 코드를 작성 해도(state.push() 같은 코드를 써도) 안전하게 불변성을 지킬 수 있게 된다.
기존에 리덕스를 사용 할 땐 이전 값을 불변성을 지키며 수정하기 위해 spread 연산자를 사용했다.
const todosReducer = createReducer([], {
[addTodo]: (state, action) => {
const todo = action.payload
return [...state, todo]
},
(...)
})
createReducer에서는 새로운 값을 반환하려면 return을 사용해주고 , 기존 값을 변형하려면 return 없이 수행하면 알아서 불변성을 지켜준다.
const todosReducer = createReducer([], {
[addTodo]: (state, action) => {
// push는 기존의 배열에 todo를 추가한다.
// 즉 배열을 mutate하지만 사용가능하다.
const todo = action.payload
state.push(todo)
},
(...)
})
configureStore : Redux DevTools Extension을 자동으로 설정해주고, 기존 리덕스의 createStore 같은 역할을 담당한다.
createAction : 액션 타입 문자열을 받아 이 타입을 사용하는 액션 생성자 함수를 반환.
createReducer : 초기 상태값과 redcuer함수에 대한 lookup테이블을 받아 이를 처리하는 reducer를 작성
createSlice : createAction과 createReducer 역할을 모두 한개의 함수에서 모두 수행한다.