Эта страница переведена 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)
Перенос 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
}
}
Библиотека для побочных эффектов на основе 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)
Инструменты разработки
Отладчики и просмотрщики
Оригинальная реализация Redux DevTools от Дэна Абрамова для отображения состояния в приложении и отладки с перемещением по времени
zalmoxisus/redux-devtools-extension
Браузерное расширение от Михаила Диордиева, которое объединяет несколько видов мониторинга состояния и добавляет интеграцию с инструментами разработчика браузера
Кроссплатформенное 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
Предложение по объединению редьюсеров, типов экшенов и самих действий