리덕스+리액트 Redux with React #6 immer 사용하기

eunji hwang·2020년 7월 14일
0

REDUX + REACT

목록 보기
6/9

immer 공식 문서

객체, 배열의 불변객체 유지하기

  • 객체 : 전개연산자 사용(...)
  • 배열 : 전개연산자 사용(...), 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를 생성하게 된다.

install

npm : npm i immer
yarn : yarn add immer
cdn : <script src="https://unpkg.com/immer"></script>

import

import produce from 'immer'

보통 produce라는 이름으로 immer를 불러온다.

produce()

produce(currentState, producer: (draftState) => void): nextState

  • currentState : 현재 state
  • draftState : 현재 state의 프록시객체(복사판같은)
  • nextState : producer 함수가 반환하는 값
const state = {
  name: 'mimi',
  age: 22,
};
const nextState = produce(currentState,( draftState) => {
  draftState.name = 'zuzu';
});

console.log(nextState);

redux에서 immer사용

// 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;
    }
  });
};

immerWrapper 만들기

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) => {},
});
profile
TIL 기록 블로그 :: 문제가 있는 글엔 댓글 부탁드려요!

0개의 댓글