...
)...
), concat
, filter
, map
등 함수사용 (push, splice등 인덱스 직접 수정 안됨!)리덕스나, state를 객체로 변경하게 되면 아래와 같은 코스 모습이 보이게 된다!
return {
...state, // userName 이외의 객체 안의 key-value를 복사해 넣고,
userName: action.payload, // userName의 key에 입력받은 값으로 대체하여
}; // 새로운 객체를 반환한다
객체 내부가 단순할 땐 문제 없지만 2차...n차 객체의 depth가 생긴다면? 복잡시럽! 코드가독성 떨어지기 시작!
이럴 땐 불변객체 관리 패키지를 사용할 것을 추천!
- 객체가 복잡/ depth가 깊다 : immer사용 추천
- 객체의 구조 단순 : 내장함수, 전개연산자 사용(
...
) 사용 추천불필요한 상황에 Immer 사용은 코드를 더 복잡하게 만든다.
immer
immer는 javascript 엔진의 proxy 기능을 사용한다. 구형브라우저, react-native 환경에서는 지원되지 않음으로 ES5-fallback(속도느린편)을 사용하게 된다. 출처 : 벨로퍼트와 함께하는 모던 리액트
immer는 currentState의 프록시객체인 임시 draftState를 생성하여 수정, nextState를 생성하게 된다.
npm : npm i immer
yarn : yarn add immer
cdn : <script src="https://unpkg.com/immer"></script>
import produce from 'immer'
보통 produce라는 이름으로 immer를 불러온다.
produce()
produce(currentState, producer: (draftState) => void): nextState
const state = {
name: 'mimi',
age: 22,
};
const nextState = produce(currentState,( draftState) => {
draftState.name = 'zuzu';
});
console.log(nextState);
// reducer.js
import produce from 'immer';
import {
FETCH_TODOS,
CREATE,
UPDATE,
DELETE,
RESET,
TOGGLE_ISLOADING,
} from './types';
const initState = {
todos: [], // { id : number, title: string }
isLoading: false,
};
export const reducer = (state = initState, action) => {
return produce(state, (draftState) => {
switch (action.type) {
case FETCH_TODOS:
draftState.todos = action.payload;
break;
case CREATE:
draftState.todos.push(action.payload);
break;
case UPDATE:
draftState.todos[action.payload.id].title = action.payload.title;
break;
case DELETE:
delete draftState.todos[action.payload];
break;
case TOGGLE_ISLOADING:
draftState.isLoading = !state.isLoading;
break;
case RESET:
draftState.todos = [];
break;
default:
break;
}
});
};
reduxtoolkit - createReducer()와 immer 기능을 합처주는 wrapper를 만들어보자.
// immerWrapper는 src/common/createReducer.js 두고 import해서 사용
import produce from 'immer';
export default function createReducer(initState, handlerMap) {
// handlerMap은 {[액션타입]:(state,acrion)=>{ 로직 }}
return function (state = initState, action) {
// immer 적용하기
return produce(state, (draft) => {
// handler = (state,acrion)=>{ 로직 }
const handler = handlerMap[action.type];
if (handler) {
// state에 자리에 draft로!
handler(draft, action);
}
});
};
}
// immerWrapper-createReducer() 사용하기
import createReducer from 'src/common/createReducer'
const reducer = createReducer (initState, {
[CREATE]: (state, action) => {
state.todos.push(todo);
},
[DELETE]: (state, action) => {},
});