redux 폴더 구조 변경하기(redux ducks pattern)

최경락 (K_ROCK_)·2022년 6월 9일
1

개요

  • 현재 연습하고 있는 레포지토리의 redux 구조는 위의 사진과 같은데, 각 컴포넌트마다 actions, reducer, types 가 전부 나뉘어 직관적이긴 하나, 수정 시에 상당히 불편하다.
  • 그래서 폴더구조를 두 방법을 이용해 수정해보고자 한다.
  • 하나는 actions, reducer, type 끼리 모아 폴더로 정리하는 방법을 사용하고, 하나는 ducks 패턴을 이용해보고자 한다.

폴더로 정리하기

  • redux 폴더는 유지한 채, 각각의 역할에 맞는 폴더로 분배 한 뒤 해당 파일의 이름을 카멜케이스를 이용하여 컴포넌트의 이름으로 변경 시키는 것으로 변경하였다.
  • combineReducerstore에 작성하지 않고, reducer 폴더에 index.ts 를 이용하여 모든 reducer들을 모아 작성한 combineReducerexport 하는 것으로 작성하였다.
// reducers/index.ts

import { combineReducers } from '@reduxjs/toolkit';

import arrayReducer from './array';
import counterReducer from './counter';
import objectReducer from './object';
import textReducer from './text';

const reducers = combineReducers({
  counterReducer,
  arrayReducer,
  textReducer,
  objectReducer,
});

export default reducers;

결과

  • 컴포넌트 별로 정리되어 있던 redux 구조를 역할 별로 정리하였다 는 것 외에는 큰 변화점은 없는 듯 하다…

redux ducks pattern

  • redux ducks pattern 는 redux 모듈을 만들기 위한 작성방식이다.
    → 여기서 redux 모듈은 하나의 파일에 action, reducer, type 이 모두 포함되어 있는 것을 이야기한다.

ducks pattern 규칙

  • ducks 패턴의 규칙은 아래와 같다.
    1. 항상 reducer()란 이름의 함수를 export default 해야한다.

    2. 항상 모듈의 action 생성자들을 함수형태로 export 해야한다.

    3. 항상 npm-module-or-app/reducer/ACTION_TYPE 형태의 action 타입을 가져야한다.

    4. 어쩌면 action 타입들을 UPPER_SNAKE_CASE로 export 할 수 있습니다.
      → 외부 reducer가 해당 action들이 발생하는지 계속 기다리거나, 재사용할 수 있는 라이브러리로 퍼블리싱할 경우.

      출처 - https://github.com/JisuPark/ducks-modular-redux

적용해보기

참고 블로그 - https://ahnanne.tistory.com/34

  • 먼저 modules 폴더를 만들어주고, 해당 폴더에 type, action, reducer 를 한 곳에 작성한 파일을 생성한다.
// module/counter.ts

// ----------------------액션 타입 작성----------------------

export const PLUS_COUNTER = 'counter/PLUS_COUNTER';
export const MINUS_COUNTER = 'counter/MINUS_COUNTER';
export const CLEAR_COUNTER = 'counter/CLEAR_COUNTER';
// 규칙 2번 참고

// ----------------------액션 함수 작성----------------------

export const plusCounter = () => {
  return {
    type: PLUS_COUNTER,
  };
};

export const minusCounter = () => {
  return {
    type: MINUS_COUNTER,
  };
};

export const clearCounter = () => {
  return {
    type: CLEAR_COUNTER,
  };
};

// ----------------------초기 상태 작성----------------------

const initialState = {
  count: 0,
};

// -----------------------리듀서 작성------------------------

function counterReducer(state = initialState, action: { type: string }) {
  switch (action.type) {
    case PLUS_COUNTER:
      return {
        ...state,
        count: state.count + 1,
      };

    case MINUS_COUNTER:
      return {
        ...state,
        count: state.count - 1,
      };

    case CLEAR_COUNTER:
      return {
        ...state,
        count: 0,
      };

    default:
      return state;
  }
}

export default counterReducer;
// 규칙 1번에 따르면 reducer로 내보내야 하지만, 이 경우 import 하는 곳에서 항상 as 문법을 이용해야 하므로 위와 같이 처리했다.

→ 하나의 파일로 합쳐친 redux 모듈의 형태.

  • modules 폴더에 index.ts 를 만들고, combineReducer를 이용하여 reducerexport 한다.
// modules/index.ts

import { combineReducers } from '@reduxjs/toolkit';

import arrayReducer from './array';
import counterReducer from './counter';
import objectReducer from './object';
import textReducer from './text';

const rootReducer = combineReducers({
  arrayReducer,
  counterReducer,
  objectReducer,
  textReducer,
});

export default rootReducer;
  • 기존 처럼 store.ts 를 만들고, 해당 파일을 export 해 사용하는 것이 아니라, index.tsx 내부에서 store를 만들고, 적용시킨다.
// src/index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

import { Provider } from 'react-redux';
import { legacy_createStore } from '@reduxjs/toolkit';

import rootReducer from './modules';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

const store = legacy_createStore(rootReducer);

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

결과

  • 아주 만족스러울 정도로 깔끔해진 것을 볼 수 있다.
  • 해당 모듈에서 사용하는 타입을 수정하는 경우에도 훨씬 더 손쉽게 가능하고, 각각의 연관관계를 한 파일에서 파악 할 수 있어서 더 좋은 듯 하다.
  • 아마, 앞으로 프로젝트를 진행하고, 전역상태를 운용해야 한다면 위처럼 작성하게 되지 않을까 생각한다.

+

  • 모듈에 작성할 내용을 스니펫으로 작성해두면 훨씬 더 상태관리를 쉽게 할 수 있을 것 같다.
  • 이제 해당 패턴으로 작성한 내용을 기반으로 toolkit에 포함된 기능들을 적용해보고, 토이 프로젝트에 적용해봐야겠다.

0개의 댓글