8. 업데이터 함수를 만들어서 코드 리팩토링하기

우리가 기존에 만들었던 리듀서를 다시 한번 확인해봅시다:

[CHANGE_INPUT]: (state, action) => ({
      ...state,
      input: action.payload,
    }),
    [CREATE]: (state, action) => ({
      ...state,
      list: state.list.concat({
        id: action.payload.id,
        name: action.payload.text,
        entered: false,
      }),
    }),
    [ENTER]: (state, action) => ({
      ...state,
      list: state.list.map(
        item =>
          item.id === action.payload
            ? { ...item, entered: !item.entered }
            : item
      ),
    }),
    [LEAVE]: (state, action) => ({
      ...state,
      list: state.list.filter(item => item.id !== action.payload),
    }),

불변성을 유지하기 위해서 ... 을 정말 많이 사용했습니다. 많이 사용한다고해서 지금 이게 잘못된것은 아니지만, 가독성이 별로 좋지 않습니다. 추가적으로, 배열을 관리할때는 배열 내장함수들을 사용하고있는데 배열 원소를 업데이트 할 때나 삭제할 때 사용하는 코드들은 지금 이렇게 액션이 별로 없을땐 상관 없지만, 리듀서에서 여러종류의 배열을 다루게 되는 일이 생긴다면 가독성이 정말 좋지 않을 것입니다.

따라서, 우리가 업데이트 할 때마다 재사용되는 코드들을 함수화하여 더 높은 가독성을 보이는 코드로 리팩토링 하는 방법을 알아보겠습니다.

updaters 만들기

우선, store 디렉토리 안에 updaters.js 파일을 만드세요:

src/updaters.js

export function updateObject(state, updated) {
  return {
    ...state,
    ...updated,
  };
}

export function updateById(array, id, updater) {
  return array.map(item => {
    if (item.id !== id) return item;
    return updater(item);
  });
}

export function removeById(array, id) {
  return array.filter(item => item.id !== id);
}

우리가 불변성을 관리하기 위하여 했던 작업들을 함수화하여 만들고 내보내주었습니다.

counter 리듀서 리팩토링

이제 우리가 만든 업데이터 함수들을 사용하여 counter 리듀서를 재작성해봅시다!

src/store/modules/counter.js
import { updateObject } from '../updaters';

// 액션 타입 정의
const CHANGE_COLOR = 'counter/CHANGE_COLOR';
const INCREMENT = 'counter/INCREMENT';
const DECREMENT = 'counter/DECREMENT';

// 액션 생섬함수 정의
export const changeColor = color => ({ type: CHANGE_COLOR, color });
export const increment = () => ({ type: INCREMENT });
export const decrement = () => ({ type: DECREMENT });

// **** 초기상태 정의
const initialState = {
  color: 'red',
  number: 0,
};

// **** 리듀서 작성
export default function counter(state = initialState, action) {
  switch (action.type) {
    case CHANGE_COLOR:
      return updateObject(state, { color: action.color });
    case INCREMENT:
      return updateObject(state, { number: state.number + 1 });
    case DECREMENT:
      return updateObject(state, { number: state.number - 1 });
    default:
      return state;
  }
}

이 리듀서에서는 기존에 ... 로 처리하던것을 updateObject 를 사용하여 처리해주었습니다. 워낙 간단한 리듀서다보니 눈에 띄는 개선사항은 많이 없습니다.

waiting 리듀서 리팩토링

이제 waiting 리듀서를 리팩토링 해보겠습니다. 우리가 만든 updateByIdremoveById 가 배열 관리 로직을 더욱 보기 좋게 해줄 것입니다.

src/modules/waiting.js

import { createAction, handleActions } from 'redux-actions';
import { updateObject, updateById, removeById } from '../updaters';

const CHANGE_INPUT = 'waiting/CHANGE_INPUT'; // 인풋 값 변경
const CREATE = 'waiting/CREATE'; // 명단에 이름 추가
const ENTER = 'waiting/ENTER'; // 입장
const LEAVE = 'waiting/LEAVE'; // 나감

let id = 3;
// createAction 으로 액션 생성함수 정의
export const changeInput = createAction(CHANGE_INPUT, text => text);
export const create = createAction(CREATE, text => ({ text, id: id++ }));
export const enter = createAction(ENTER, id => id);
export const leave = createAction(LEAVE, id => id);

// 초기 상태 정의
const initialState = {
  input: '',
  list: [
    {
      id: 0,
      name: '홍길동',
      entered: true,
    },
    {
      id: 1,
      name: '콩쥐',
      entered: false,
    },
    {
      id: 2,
      name: '팥쥐',
      entered: false,
    },
  ],
};

// handleActions 로 리듀서 함수 작성
export default handleActions(
  {
    [CHANGE_INPUT]: (state, action) =>
      updateObject(state, { input: action.payload }),
    [CREATE]: (state, action) =>
      updateObject(state, {
        list: state.list.concat({
          id: action.payload.id,
          name: action.payload.text,
          entered: false,
        }),
      }),
    [ENTER]: (state, action) =>
      updateObject(state, {
        list: updateById(state.list, action.payload, item =>
          updateObject(item, { entered: !item.entered })
        ),
      }),
    [LEAVE]: (state, action) =>
      updateObject(state, {
        list: removeById(state.list, action.payload),
      }),
  },
  initialState
);

Edit colorful-counter [code refactoring]

이 리듀서에서는 ENTER 과 LEAVE 에서 업데이터 함수를 중첩해서 사용하기도 했습니다. 이제 코드를 봤을때 어떤 작업을 하고 있는지 한 눈에 알아보기 쉬워졌습니다!

results matching ""

    No results matching ""