본문으로 바로가기

ducks-moduar-redux 번역

category 카테고리 없음 2022. 7. 27. 19:38

원문 : https://github.com/erikras/ducks-modular-redux

Ducks: Redux Reducer Bundles

저는 Redux 어플리케이션을 구축하던 와중, 한번에 한가지 기능을 만들때 각각의 용도에 따라 개별의 파일로 {actionTypes, actions, reducer} 를 계속 추가해야 된다는 것을 깨달았습니다.

지금까지는 각각의 분리된 폴더에 파일을 나누는 구조를 사용했지만, 대부분의 경우(대략 95%정도) reducer와 actions만이 서로 연관된 동작을 필요로 합니다.

제가 느끼기기에는 각각의 파일로 나누는것 보다 하나의 파일로 번들링하여 사용하는편이 더 효율적이고, 라이브러리로 쉽게 패키징하는것이 가능해집니다.

내가 생각하는 방안

예시

// widgets.js

// Actions
const LOAD = "my-app/widgets/LOAD";
const CREATE = "my-app/widgets/CREATE";
const UPDATE = "my-app/widgets/UPDATE";
const REMOVE = "my-app/widgets/REMOVE";

// Reducer
export default function reducer(state = {}, action = {}) {
  switch (action.type) {
    // do reducer stuff
    default:
      return state;
  }
}

// Action Creators
export function loadWidgets() {
  return { type: LOAD };
}

export function createWidget(widget) {
  return { type: CREATE, widget };
}

export function updateWidget(widget) {
  return { type: UPDATE, widget };
}

export function removeWidget(widget) {
  return { type: REMOVE, widget };
}

// side effects, only as applicable
// e.g. thunks, epics, etc
export function getWidget() {
  return (dispatch) =>
    get("/widget").then((widget) => dispatch(updateWidget(widget)));
}

참고: Common JS Example

규칙

하나의 모듈은

  1. reducer()란 이름의 함수는 반드시 export default되어야 합니다
  2. action 생성자 함수들은 반드시 export되어야 합니다
  3. 액션 타입은 반드시 npm-module-or-app/reducer/ACTION_TYPE와 같은 형태여야만 합니다
  4. 외부 리듀서에서 액션 타입을 받아와야 하거나, 재사용가능한 라이브러리로 만들 경우 UPPER_SNAKE_CASE와 같은 액션 타입이 export 될수도 있습니다.

{actionType, action, reducer}와 같은 모듈들을 라이브러리화 시킬 경우에도 같은 가이드라인을 사용하는것을 추천합니다.

명칭

Java에는 jars와 beans이 있습니다. Ruby에는 gems이 있고요. 저는 위와 같은 reducer 모듈화 방법론을 "redux"의 마지막 음절을 따서 "ducks"라고 부르고자 합니다.

사용법

우리는 여전히 아래와 같이 사용할 수 있습니다

import { combineReducers } from "redux";
import * as reducers from "./ducks/index";

const rootReducer = combineReducers(reducers);
export default rootReducer;

또한 아래처럼 사용할 수도 있고요

import * as widgetActions from "./ducks/widgets";

그리고 bindActionCreators()에 넘겨줄 수 있도록 action 생성자만을 import해줍니다.

어떤 경우 action가 아닌 다른 무언가를 export하고 싶을 수 있습니다. 충분히 이해합니다. 제가 말했던 규칙은 오로지 action 생성자만을 export할 수 있다는 의미는 아닙니다. action 생성자 외에 다른것을 export하고 싶을 경우 비구조화 할당을 사용할 수 있습니다.

import {
  loadWidgets,
  createWidget,
  updateWidget,
  removeWidget,
} from "./ducks/widgets";
// ...
bindActionCreators(
  { loadWidgets, createWidget, updateWidget, removeWidget },
  dispatch
);

예시

React Redux Universal Hot Example은 ducks패턴을 따르고 있습니다. /src/redux/modules를 참고하세요.

제네레이터

BattleCry를 사용하면 ducks패턴을 설정하는데 도움을 줄 수 있습니다.

npm install -g battlecry
cry download generator erikras/ducks-modular-redux
cry init duck

cry --help 명령어로 제네레이터에 대한 더 많은 정보를 볼 수 있습니디.

실행하기

이러한 패턴으로 코드를 마이그레이션 하는 것은 어렵지 않습니다, 그리고 저는 이러한 방식이 추후 다가올 고통을 줄여주는데 도움이 될 것이라고 생각합니다.

이는 별도의 라이브러리 없이도 구현할 수 있으나, 몇가지 툴이 당신을 도울 수도 있을지도 모릅니다.

  • extensible-duck - Implementation of the Ducks proposal. With this library you can create reusable and extensible ducks.
  • saga-duck - Implementation of the Ducks proposal in Typescript with sagas in mind. Results in reusable and extensible ducks.
  • redux-duck - Helper function to create Redux modules using the ducks-modular-redux proposal
  • modular-redux-thunk - A ducks-inspired package to help organize actions, reducers, and selectors together - with built-in redux-thunk support for async actions.
  • molecular-js - Set of utilities to ease the development of modular state management patterns with Redux (also known as ducks).
  • ducks-reducer - Function to combine ducks object reducers into one reducer (equivalent to combineReducers), and function ducks-middleware to combine ducks object middleware into one single middleware compatible with applyMiddleware.
  • simple-duck - Class based implementation of modules system, inspired by ducks-modular-redux. All OOP benefits like inheritance and composition. Support combining of duck-module classes and regular reducer functions using combineModules function.

피드백은 @erikras로 보내주시면 감사하겠습니다.

Happy coding!

-- Erik Rasmussen