-
Notifications
You must be signed in to change notification settings - Fork 0
reducer를 커스텀하기
react는 익히 알다시피 얕은 비교를 통해 상태 관리를 한다. 이말은 즉 얕은 비교를 하기 때문에 push등의 직접적인 변경을 하게 될 경우 react가 변화를 감지하지 못하여 리렌더링하지 않는다는 것이다.
하지만 전개연산자를 이용해 매번 값을 변경하는것은 꽤 불편한 일이다. 또한 깊이가 깊어질수록 더욱 불편하다.
immer의 경우 공식문서를 살펴보면 Immer simplifies handling immutable data structures
라고 되어있다. 따라서 immer를 사용하게 되었다.
우선 immer의 사용법에 대해 알아보자.
공식문서에서 보자면,
라고 되어있다.
produce를 통하여 불변객체를 관리하는데, 첫번째 인자로는 상태값을 넣어준다. 두번째 인자로는 draft를 인자로 두어 항태를 변경할 함수를 전달한다.
import produce from "immer"
const nextState = produce(baseState, draft => {
draft[1].done = true
draft.push({title: "Tweet about it"})
})
const baseState = [
/* as is */
]
const nextState = toggleTodo(baseState, "Immer")
이러한 식으로 되어있다. 즉 현재값을 draft를 통해 변경해주면 되는 것이다.
하지만 모든 reducer에서 produce를 통해 값을 변경하기에는 불편한 방법이 될 수 있다. 따라서 custom reducer를 만들어 주었다.
export function createReducer(initialState, handlerMap) {
return function (state = initialState, action) {
const handler = handlerMap[action.type];
if (handler) {
return produce(state, (draft) => {
handler(draft, action);
});
} else {
return state;
}
};
}
createReducer는 두개의 파라미터를 받아서 초기 설정을 한다.
다음으로 액션이 들어온다면, 액션에 맞는 핸들러를 찾아서 produce를 해준다.
예를들어 SetUser라는 액션 타입을 호출했을때
(state, action) => {
state.name = action.name;
state.isLogin = action.name ? "Login" : "NotLogin";
},
이러한 handler가 매핑이 되게된다.
그 다음 handler가 존재한다면 produce를 반환한다.
초반엔 INIT이 액션에 들어가기 때문에 handler가 없기 때문에 따라서 hander가 없는 경우 예외 처리를 꼭 해주어야 한다. (이것 때문에 에러 찾는데 오래 걸렸다...)
이렇게 createReducer를 만들어 주었다면 리듀서에서 따로 불변성을 신경쓸 필요없이 사용할 수 있다.
const reducer = createReducer(INITIAL_STATE, {
[Types.SetUser]: (state, action) => {
state.name = action.name;
state.isLogin = action.name ? "Login" : "NotLogin";
},
});
참고 문서📖
immer docs