Перейти к основному содержимому
Неофициальный Бета-перевод

Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →

Экосистема

Redux — это небольшая библиотека, но её контракты и API тщательно продуманы для создания экосистемы инструментов и расширений. Сообщество разработало множество полезных дополнений, библиотек и инструментов. Вам не обязательно использовать эти дополнения для работы с Redux, но они могут упростить реализацию функций и решение задач в вашем приложении.

Для полного каталога библиотек, дополнений и инструментов, связанных с Redux, ознакомьтесь со списком Ссылки на экосистему Redux. Также список Ссылки React/Redux содержит учебные материалы и другие полезные ресурсы для тех, кто изучает React или Redux.

На этой странице перечислены некоторые дополнения для Redux, которые лично проверили сопровождающие Redux или которые получили широкое распространение в сообществе. Не стоит ограничиваться только ими! Экосистема развивается слишком быстро, и у нас не хватает времени на всё. Считайте это "выбором редакции" — и не стесняйтесь отправлять PR, если создали что-то замечательное с помощью Redux.

Содержание

Интеграция библиотек и привязки

reduxjs/react-redux
Официальные привязки Redux для React, поддерживаемые командой Redux

angular-redux/ng-redux
Привязки Redux для Angular 1

ember-redux/ember-redux
Привязки Redux для Ember

glimmer-redux/glimmer-redux
Привязки Redux для компонентного движка Glimmer (Ember)

tur-nr/polymer-redux
Привязки Redux для Polymer

lastmjs/redux-store-element Привязки Redux для пользовательских элементов

Редюсеры

Комбинация редюсеров

ryo33/combineSectionReducers
Расширенная версия combineReducers, позволяющая передавать state в качестве третьего аргумента во все частичные редюсеры.

KodersLab/topologically-combine-reducers
Вариация combineReducers, позволяющая определять межмодульные зависимости для упорядочивания и передачи данных

var masterReducer = topologicallyCombineReducers(
{ auth, users, todos },
// define the dependency tree
{ auth: ['users'], todos: ['auth'] }
)

Композиция редюсеров

acdlite/reduce-reducers
Обеспечивает последовательную композицию редюсеров на одном уровне

const combinedReducer = combineReducers({ users, posts, comments })
const rootReducer = reduceReducers(combinedReducer, otherTopLevelFeatureReducer)

mhelmer/redux-xforms
Коллекция композируемых трансформаторов редюсеров

const createByFilter = (predicate, mapActionToKey) =>
compose(
withInitialState({}), // inject initial state as {}
withFilter(predicate), // let through if action has filterName
updateSlice(mapActionToKey), // update a single key in the state
isolateSlice(mapActionToKey) // run the reducer on a single state slice
)

adrienjt/redux-data-structures
Фабричные функции редюсеров для распространённых структур данных: счётчики, словари, списки (очереди, стеки), множества

const myCounter = counter({
incrementActionTypes: ['INCREMENT'],
decrementActionTypes: ['DECREMENT']
})

Редюсеры высшего порядка

omnidan/redux-undo
Беспроблемное undo/redo и история действий для ваших редюсеров

omnidan/redux-ignore
Игнорирование действий Redux по массиву или фильтрующей функции

omnidan/redux-recycle
Сброс состояния Redux при определённых действиях

ForbesLindesay/redux-optimist
Усилитель редюсера для реализации оптимистичных обновлений без привязки к типам

Утилиты

reduxjs/reselect
Создаёт композируемые мемоизированные селекторы для эффективного извлечения данных из состояния хранилища

const taxSelector = createSelector(
[subtotalSelector, taxPercentSelector],
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
)

paularmstrong/normalizr
Нормализует вложенный JSON согласно схеме

const user = new schema.Entity('users')
const comment = new schema.Entity('comments', { commenter: user })
const article = new schema.Entity('articles', {
author: user,
comments: [comment]
})
const normalizedData = normalize(originalData, article)

planttheidea/selectorator
Абстракции над Reselect для распространённых сценариев использования селекторов

const getBarBaz = createSelector(
['foo.bar', 'baz'],
(bar, baz) => `${bar} ${baz}`
)
getBarBaz({ foo: { bar: 'a' }, baz: 'b' }) // "a b"

Хранилище (Store)

Подписки на изменения

jprichardson/redux-watch
Отслеживание изменений состояния по ключевым путям или селекторам

let w = watch(() => mySelector(store.getState()))
store.subscribe(
w((newVal, oldVal) => {
console.log(newval, oldVal)
})
)

ashaffer/redux-subscribe
Централизованные подписки на изменения состояния по путям

store.dispatch( subscribe("users.byId.abcd", "subscription1", () => {} );

Группировка (Batching)

tappleby/redux-batched-subscribe
Усилитель хранилища, позволяющий дебаунсить уведомления подписок

const debounceNotify = _.debounce(notify => notify())
const store = configureStore({
reducer,
enhancers: [batchedSubscribe(debounceNotify)]
})

manaflair/redux-batch
Усилитель хранилища, позволяющий диспетчеризовать массивы действий

const store = configureStore({
reducer,
enhancers: existingEnhancersArray => [
reduxBatch,
...existingEnhancersArray,
reduxBatch
]
})
store.dispatch([{ type: 'INCREMENT' }, { type: 'INCREMENT' }])

laysent/redux-batch-actions-enhancer
Усилитель хранилища, принимающий групповые действия

const store = configureStore({ reducer, enhancers: [batch().enhancer] })
store.dispatch(createAction({ type: 'INCREMENT' }, { type: 'INCREMENT' }))

tshelburne/redux-batched-actions
Редюсер высшего порядка, обрабатывающий групповые действия

const store = configureStore({ reducer: enableBatching(rootReducer) })
store.dispatch(batchActions([{ type: 'INCREMENT' }, { type: 'INCREMENT' }]))

Сохранение состояния (Persistence)

rt2zz/redux-persist
Сохранение и восстановление состояния Redux-хранилища с множеством расширяемых опций

const persistConfig = { key: 'root', version: 1, storage }
const persistedReducer = persistReducer(persistConfig, rootReducer)
export const store = configureStore({
reducer: persistedReducer,
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
}
})
})
export const persistor = persistStore(store)

react-stack/redux-storage
Слой сохранения состояния для Redux с гибкими бэкендами

const reducer = storage.reducer(combineReducers(reducers))
const engine = createEngineLocalStorage('my-save-key')
const storageMiddleware = storage.createMiddleware(engine)
const store = configureStore({
reducer,
middleware: getDefaultMiddleware =>
getDefaultMiddleware.concat(storageMiddleware)
})

redux-offline/redux-offline
Постоянное хранилище для Offline-First приложений с поддержкой оптимистичных интерфейсов

const store = configureStore({ reducer, enhancer: [offline(offlineConfig)] })
store.dispatch({
type: 'FOLLOW_USER_REQUEST',
meta: { offline: { effect: {}, commit: {}, rollback: {} } }
})

Неизменяемые данные

ImmerJS/immer
Неизменяемые обновления с помощью обычного мутабельного кода через Proxies

const nextState = produce(baseState, draftState => {
draftState.push({ todo: 'Tweet about it' })
draftState[1].done = true
})

Побочные эффекты

Широко используемые решения

reduxjs/redux-thunk
Диспетчеризация функций, которые вызываются с параметрами dispatch и getState. Позволяет обрабатывать AJAX-запросы и другую асинхронную логику.

Лучше всего подходит для: начального обучения, простой асинхронной и сложной синхронной логики.

function fetchData(someValue) {
return (dispatch, getState) => {
dispatch({type : "REQUEST_STARTED"});

myAjaxLib.post("/someEndpoint", {data : someValue})
.then(response => dispatch({type : "REQUEST_SUCCEEDED", payload : response})
.catch(error => dispatch({type : "REQUEST_FAILED", error : error});
};
}

function addTodosIfAllowed(todoText) {
return (dispatch, getState) => {
const state = getState();

if(state.todos.length < MAX_TODOS) {
dispatch({type : "ADD_TODO", text : todoText});
}
}
}

listenerMiddleware (Redux Toolkit)
listenerMiddleware предлагает более лёгкую альтернативу популярным middleware для асинхронных операций в Redux, таким как саги и observable. При схожей сложности с thunks, позволяет воспроизвести некоторые паттерны использования саг.

listenerMiddleware.startListening({
matcher: isAnyOf(action1, action2, action3),
effect: (action, listenerApi) => {
const user = selectUserDetails(listenerApi.getState())

const { specialData } = action.meta

analyticsApi.trackUsage(action.type, user, specialData)
}
})

redux-saga/redux-saga
Обработка асинхронной логики через синхронно выглядящие функции-генераторы. Саги возвращают описания эффектов, которые исполняются middleware и работают как "фоновые потоки" в JS-приложениях.

Лучше всего подходит для: сложной асинхронной логики, разделённых workflow

function* fetchData(action) {
const { someValue } = action
try {
const response = yield call(myAjaxLib.post, '/someEndpoint', {
data: someValue
})
yield put({ type: 'REQUEST_SUCCEEDED', payload: response })
} catch (error) {
yield put({ type: 'REQUEST_FAILED', error: error })
}
}

function* addTodosIfAllowed(action) {
const { todoText } = action
const todos = yield select(state => state.todos)

if (todos.length < MAX_TODOS) {
yield put({ type: 'ADD_TODO', text: todoText })
}
}

redux-observable/redux-observable

Обработка асинхронной логики через цепочки RxJS observable ("epics"). Композиция и отмена асинхронных действий для создания побочных эффектов.

Лучше всего подходит для: сложной асинхронной логики, разделённых workflow

const loginRequestEpic = action$ =>
action$
.ofType(LOGIN_REQUEST)
.mergeMap(({ payload: { username, password } }) =>
Observable.from(postLogin(username, password))
.map(loginSuccess)
.catch(loginFailure)
)

const loginSuccessfulEpic = action$ =>
action$
.ofType(LOGIN_SUCCESS)
.delay(2000)
.mergeMap(({ payload: { msg } }) => showMessage(msg))

const rootEpic = combineEpics(loginRequestEpic, loginSuccessfulEpic)

redux-loop/redux-loop

Перенос Elm Architecture в Redux, позволяющий естественно описывать эффекты через возврат их из редюсеров. Редюсеры возвращают как состояние, так и описание побочных эффектов.

Лучше всего подходит для: максимального приближения к Elm в связке Redux+JS

export const reducer = (state = {}, action) => {
switch (action.type) {
case ActionType.LOGIN_REQUEST:
const { username, password } = action.payload
return loop(
{ pending: true },
Effect.promise(loginPromise, username, password)
)
case ActionType.LOGIN_SUCCESS:
const { user, msg } = action.payload
return loop(
{ pending: false, user },
Effect.promise(delayMessagePromise, msg, 2000)
)
case ActionType.LOGIN_FAILURE:
return { pending: false, err: action.payload }
default:
return state
}
}

jeffbski/redux-logic

Библиотека для побочных эффектов на основе observable, поддерживающая колбэки, промисы, async/await и observable. Предоставляет декларативную обработку действий.

Лучше всего подходит для: максимально разделённой асинхронной логики

const loginLogic = createLogic({
type: Actions.LOGIN_REQUEST,

process({ getState, action }, dispatch, done) {
const { username, password } = action.payload

postLogin(username, password)
.then(
({ user, msg }) => {
dispatch(loginSucceeded(user))

setTimeout(() => dispatch(showMessage(msg)), 2000)
},
err => dispatch(loginFailure(err))
)
.then(done)
}
})

Работа с промисами

acdlite/redux-promise
Диспетчеризация промисов как payload действий с автоматической отправкой FSA-совместимых действий при разрешении/отклонении промиса.

dispatch({ type: 'FETCH_DATA', payload: myAjaxLib.get('/data') })
// will dispatch either {type : "FETCH_DATA", payload : response} if resolved,
// or dispatch {type : "FETCH_DATA", payload : error, error : true} if rejected

lelandrichardson/redux-pack
Продуманная декларативная обработка промисов по конвенциям, направляющая пользователей без предоставления полного контроля над dispatch.

dispatch({type : "FETCH_DATA", payload : myAjaxLib.get("/data") });

// in a reducer:
case "FETCH_DATA": =
return handle(state, action, {
start: prevState => ({
...prevState,
isLoading: true,
fooError: null
}),
finish: prevState => ({ ...prevState, isLoading: false }),
failure: prevState => ({ ...prevState, fooError: payload }),
success: prevState => ({ ...prevState, foo: payload }),
});

Middleware

Сети и сокеты

svrcekmichal/redux-axios-middleware
Получение данных через Axios с автоматической диспетчеризацией действий start/success/fail

export const loadCategories() => ({ type: 'LOAD', payload: { request : { url: '/categories'} } });

agraboso/redux-api-middleware
Чтение действий вызовов API, выполнение запросов и диспетчеризация FSA

const fetchUsers = () => ({
[CALL_API]: {
endpoint: 'http://www.example.com/api/users',
method: 'GET',
types: ['REQUEST', 'SUCCESS', 'FAILURE']
}
})

itaylor/redux-socket.io
Опинионированный коннектор между socket.io и redux.

const store = configureStore({
reducer,
middleware: getDefaultMiddleware =>
getDefaultMiddleware.concat(socketIoMiddleware)
})
store.dispatch({ type: 'server/hello', data: 'Hello!' })

tiberiuc/redux-react-firebase
Интеграция между Firebase, React и Redux

Асинхронное поведение

rt2zz/redux-action-buffer
Буферизует все действия в очередь до выполнения условия прерывания, после чего очередь освобождается

wyze/redux-debounce
FSA-совместимое middleware для Redux, устраняющее дребезг действий.

mathieudutour/redux-queue-offline
Ставит действия в очередь при работе офлайн и отправляет их при восстановлении соединения.

Аналитика

rangle/redux-beacon
Интегрируется с любыми аналитическими сервисами, работает офлайн и отделяет логику аналитики от логики приложения

markdalgleish/redux-analytics
Отслеживает FSA-действия с метаданными аналитики и обрабатывает их

Сущности и коллекции

tommikaikkonen/redux-orm
Простой иммутабельный ORM для управления реляционными данными в хранилище Redux.

Versent/redux-crud
Действия и редьюсеры на основе соглашений для CRUD-логики

kwelch/entities-reducer
Higher-order редьюсер для обработки данных из Normalizr

amplitude/redux-query
Объявление зависимостей данных совместно с компонентами, выполнение запросов при монтировании, оптимистичные обновления и триггеры серверных изменений через Redux-действия.

cantierecreativo/redux-bees
Декларативное взаимодействие с JSON-API с нормализацией данных и HOC для React, выполняющим запросы

GetAmbassador/redux-clerk
Асинхронная обработка CRUD с нормализацией, оптимистичными обновлениями, синхронными/асинхронными создателями действий, селекторами и расширяемым редьюсером.

shoutem/redux-io
Абстракция JSON-API с асинхронным CRUD, нормализацией, оптимистичными обновлениями, кэшированием, статусами данных и обработкой ошибок.

jmeas/redux-resource
Компактная система для управления "ресурсами": данными, сохраняемыми на удалённых серверах.

Состояние компонентов и инкапсуляция

threepointone/redux-react-local
Локальное состояние компонентов в Redux с обработкой их действий

@local({
ident: 'counter', initial: 0, reducer : (state, action) => action.me ? state + 1 : state }
})
class Counter extends React.Component {

epeli/lean-redux
Обеспечивает управление состоянием компонентов в Redux, простое как setState

const DynamicCounters = connectLean(
scope: "dynamicCounters",
getInitialState() => ({counterCount : 1}),
addCounter, removeCounter
)(CounterList);

DataDog/redux-doghouse
Упрощает создание переиспользуемых компонентов в Redux путём ограничения действий и редьюсеров конкретными экземплярами компонентов.

const scopeableActions = new ScopedActionFactory(actionCreators)
const actionCreatorsScopedToA = scopeableActions.scope('a')
actionCreatorsScopedToA.foo('bar') //{ type: SET_FOO, value: 'bar', scopeID: 'a' }

const boundScopeableActions = bindScopedActionFactories(
scopeableActions,
store.dispatch
)
const scopedReducers = scopeReducers(reducers)

Инструменты разработки

Отладчики и просмотрщики

reduxjs/redux-devtools

Оригинальная реализация Redux DevTools от Дэна Абрамова для отображения состояния в приложении и отладки с перемещением по времени

zalmoxisus/redux-devtools-extension

Браузерное расширение от Михаила Диордиева, которое объединяет несколько видов мониторинга состояния и добавляет интеграцию с инструментами разработчика браузера

infinitered/reactotron

Кроссплатформенное Electron-приложение для инспекции React и React Native приложений, включая состояние приложения, API-запросы, производительность, ошибки, саги и диспетчеризацию действий.

Мониторы для DevTools

Log Monitor
Стандартный монитор Redux DevTools с древовидным представлением

Dock Monitor
Изменяемый и перемещаемый док для мониторов Redux DevTools

Slider Monitor
Кастомный монитор для Redux DevTools, воспроизводящий записанные действия Redux

Diff Monitor
Монитор для Redux DevTools, показывающий различия в состоянии хранилища между действиями

Filterable Log Monitor
Древовидный монитор для Redux DevTools с возможностью фильтрации

Filter Actions
Компонуемый монитор Redux DevTools с фильтрацией действий

Логирование

evgenyrodionov/redux-logger
Мидлварь для логирования, отображающая действия, состояния и различия

inakianduaga/redux-state-history
Расширение, предоставляющее возможность "путешествий во времени" и эффективной записи действий, включая импорт/экспорт логов и их воспроизведение.

joshwcomeau/redux-vcr
Запись и воспроизведение пользовательских сессий в реальном времени

socialtables/redux-unhandled-action
Предупреждает о действиях, которые не привели к изменениям состояния (в режиме разработки)

Обнаружение мутаций

leoasis/redux-immutable-state-invariant
Мидлварь, вызывающая ошибку при попытке мутации состояния во время диспетчеризации или между диспетчеризациями.

flexport/mutation-sentinel
Помогает глубоко обнаруживать мутации во время выполнения и обеспечивать иммутабельность в кодовой базе.

mmahalwy/redux-pure-connect
Проверяет и логирует, передаются ли в метод connect из react-redux функции mapState, создающие нечистые пропсы.

Тестирование

arnaudbenard/redux-mock-store
Мок-хранилище, сохраняющее диспетчеризованные действия в массиве для проверок

Workable/redux-test-belt
Расширяет API хранилища для упрощения проверок, изоляции и манипуляций с состоянием

conorhastings/redux-test-recorder
Мидлварь для автоматической генерации тестов редьюсеров на основе действий в приложении

wix/redux-testkit
Полный и предвзятый (opinionated) набор инструментов для тестирования проектов Redux (редьюсеры, селекторы, экшены, thunks)

jfairbank/redux-saga-test-plan
Значительно упрощает интеграционное и модульное тестирование саг

Маршрутизация (Routing)

supasate/connected-react-router Синхронизирует состояние React Router v4+ с вашим Redux-хранилищем.

faceyspacey/redux-first-router
Бесшовная Redux-first маршрутизация. Представляйте приложение через состояния, а не маршруты или компоненты, сохраняя синхронизацию адресной строки. Всё — это состояние. Подключайте компоненты и просто диспатчьте стандартные экшены Flux.

Формы

erikras/redux-form
Многофункциональная библиотека для хранения состояния React HTML-форм в Redux.

davidkpiano/react-redux-form
Набор создателей редьюсеров и экшенов, упрощающий создание даже самых сложных кастомных форм на React и Redux с высокой производительностью.

Абстракции высокого уровня

keajs/kea
Абстракция над Redux, Redux-Saga и Reselect. Предоставляет фреймворк для экшенов, редьюсеров, селекторов и саг вашего приложения. Упрощает использование Redux до уровня setState, сокращает шаблонный код при сохранении композируемости.

TheComfyChair/redux-scc
Использует определённую структуру и "поведения" (behaviors) для создания наборов экшенов, реакций редьюсеров и селекторов.

Bloomca/redux-tiles
Минимальная абстракция поверх Redux для лёгкой композиции, простых асинхронных запросов и удобного тестирования.

Конвенции сообщества

Flux Standard Action
Удобный для человека стандарт объектов действий Flux

Canonical Reducer Composition
Предвзятый стандарт композиции вложенных редьюсеров

Ducks: Redux Reducer Bundles
Предложение по объединению редьюсеров, типов экшенов и самих действий