При написании redux приложений я замечаю, что работая над отдельными частями своего функционала, мне каждый раз приходится добавлять {actionTypes, actions, reducer}
. Я храню их в разных файлах и даже в разных директориях, однако, в 95% процентах случаев требуется лишь одна пара reducer/actions для их связанных действий.
Как по мне, логичнее объединять эти части в самодостаточные изолированные модули, которые с легкостью можно даже упаковать в библиотеку.
Смотрите также: Общий JS Пример.
// 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 };
}
// сайд-эффекты, только подходящие
// например, thunks, epics, и т.д.
export function getWidget () {
return dispatch => get('/widget').then(widget => dispatch(updateWidget(widget)))
}
Модуль...
- ДОЛЖЕН делать
export default
функцииreducer()
- ДОЛЖЕН делать
export
action creators как функций - ДОЛЖЕН иметь action types в виде
npm-module-or-app/reducer/ACTION_TYPE
- МОЖЕТ экспортировать action types как
UPPER_SNAKE_CASE
, если внешнему reducer нужно следить за событиями этих типов или если это опубликованная переиспользуемая библиотека.
Те же правила рекомендуемы для {actionType, action, reducer}
пакетов, что используются как переиспользуемые Redux библиотеки.
У Java есть jars и beans. У Ruby есть gems. Я предлагаю называть эти reducer пакеты "ducks" (от англ. "утки"), как последний слог в слове "redux".
Вы все еще можете:
import { combineReducers } from 'redux';
import * as reducers from './ducks/index';
const rootReducer = combineReducers(reducers);
export default rootReducer;
Вы все еще можете:
import * as widgetActions from './ducks/widgets';
...и это будет делать import только функций action creators, чтобы быть переданными функции bindActionCreators()
.
Вообще говоря, это выражение также сделает import
default
, результатом которого станет функция reducer. Это добавит функцию action creator, названнуюdefault
, которая не будет работать. Если это проблема, вам следует перечислять каждую функцию action creator во время импортирования.
Будет время, когда вам захочется экспортировать что-то помимо функций action creators. Это также нормально. Правила не говорят, что вы можете делать исключительно export
функций action creators. Когда вам понадобится делать export
функций action creators, вам всего лишь нужно перечислить те из них, что вам нужны. Ничего серьезного.
import {loadWidgets, createWidget, updateWidget, removeWidget} from './ducks/widgets';
// ...
bindActionCreators({loadWidgets, createWidget, updateWidget, removeWidget}, dispatch);
React Redux Универсальный Горячий Пример, использующий ducks. Смотрите /src/redux/modules
.
Существуют конфигурируемые BattleCry генераторы, готовые к скачиванию и оказанию помощи для написания ducks:
npm install -g battlecry
cry download generator erikras/ducks-modular-redux
cry init duck
Запустите cry --help
, чтобы получить больше информации о возможных генераторах;
Миграция на такую структура кода была безболезненной, и я предвижу, что в будущем это уменьшит проблемы при разработке.
Хотя реализовать ducks возможно без какой-либо внешней библиотеки, существует несколько инструментов, что могут вам помочь:
- extensible-duck - Реализация Ducks. С этой библиотекой вы можете создать переиспользуемые и расширяемые ducks.
- saga-duck - Реализация Ducks в Typescript с sagas. Результаты в переиспользуемых и расширяемых ducks.
- redux-duck - Функция-помощник для создания Redux-модулей, использующих ducks-modular-redux принцип.
- modular-redux-thunk - Вдохновленный принципом ducks пакет для помощи в организации actions, функций reducers, и селекторов вместе - со встроенной redux-thunk поддержкой для асинхронных actions.
- molecular-js - Набор утилит, чтобы облегчить разработку шаблонов модульного управления состоянием (modular state management) с библиотекой Redux (также изв. как ducks).
- ducks-reducer - Функция для объединения ducks object функций-reducers в одну функцию-reducer (эквивалентной функции combineReducers), и функции ducks-middleware для объединения ducks object middleware в одну middleware, совместимую с applyMiddleware.
- simple-duck - Реализация модульной системы, основанная на классах, вдохновленная ducks-modular-redux. Включает такие преимущества ООП, как наследование и композиция. Поддерживает объединение классов duck-модулей и обычных функций-reducer используя
combineModules
функцию.
Пожалуйста, оставьте обратную связь через issue или твит на @erikras. Буду крайне признателен.
Счастливого кодинга!
-- Erik Rasmussen
Фото Airwolfhound.