Skip to main content

生态系统

Redux 是一个小巧的库,但它的契约和 API 精心设计,催生了一个工具和扩展的生态系统,社区创建了各种有用的插件、库和工具。你不需要使用任何这些插件来使用 Redux,但它们可以帮助你更容易地实现功能和解决应用中的问题。

想要查看与 Redux 相关的库、插件和工具的广泛目录,请查阅 Redux Ecosystem Links 列表。此外,React/Redux Links 列表包含了针对学习 React 或 Redux 的人有用的教程和其他资源。

本页列出了一些 Redux 维护者亲自审阅过,或在社区中被广泛采用的 Redux 相关插件。不要因为没在这里找到的插件而气馁!生态系统发展太快,我们没有足够时间覆盖所有内容。把这些看作是“官方精选”,如果你用 Redux 创造了很棒的东西,欢迎提交 PR。

目录

库集成与绑定

reduxjs/react-redux
Redux 官方的 React 绑定,由 Redux 团队维护

angular-redux/ng-redux
Angular 1 绑定 Redux

ember-redux/ember-redux
Ember 绑定 Redux

glimmer-redux/glimmer-redux
适用于 Ember 的 Glimmer 组件引擎的 Redux 绑定

tur-nr/polymer-redux
Redux 绑定 Polymer

lastmjs/redux-store-element
Redux 绑定自定义元素

Reducer

Reducer 组合

ryo33/combineSectionReducers
combineReducers 的增强版本,允许传递 state 作为第三参数给所有切片 reducers。

KodersLab/topologically-combine-reducers
一种变体 combineReducers,允许运行切片之间的依赖关系定义,用于排序和数据传递

var masterReducer = topologicallyCombineReducers(
{ auth, users, todos },
// 定义依赖树
{ auth: ['users'], todos: ['auth'] }
)

Reducer 组合式

acdlite/reduce-reducers
提供同级 reducer 的顺序组合

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

mhelmer/redux-xforms
一组可组合的 reducer 转换器集合

const createByFilter = (predicate, mapActionToKey) =>
compose(
withInitialState({}), // 注入初始状态 {}
withFilter(predicate), // 仅通过 action 具备 filterName 时
updateSlice(mapActionToKey), // 更新状态中单个键
isolateSlice(mapActionToKey) // 在单个状态切片上运行 reducer
)

adrienjt/redux-data-structures
通用数据结构的 reducer 工厂函数:计数器,MAP,列表(队列,栈),集合等

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

高阶 Reducer

omnidan/redux-undo
轻松实现撤销/重做以及动作历史管理

omnidan/redux-ignore
通过数组或过滤函数忽略 Redux 动作

omnidan/redux-recycle
在特定动作时重置 Redux 状态

ForbesLindesay/redux-optimist
用于启用类型无关乐观更新的 reducer 增强器

工具

reduxjs/reselect
创建可组合的备忘选择器函数,用于高效派生 store 状态数据

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

paularmstrong/normalizr
根据 schema 标准化嵌套 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", () => {} );

批处理

tappleby/redux-batched-subscribe
可以防抖订阅通知的 store 增强器

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

manaflair/redux-batch
允许派发动作数组的 store 增强器

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

laysent/redux-batch-actions-enhancer
接受批量动作的 store 增强器

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

tshelburne/redux-batched-actions
处理批量动作的高阶 reducer

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

持久化

rt2zz/redux-persist
持久化并重新加载 Redux store,提供丰富的可扩展选项

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
支持乐观 UI 的断网优先应用的持久化 store

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

不可变数据

ImmerJS/immer
使用 Proxy 实现普通命令式代码的不可变更新

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

副作用

广泛使用

reduxjs/redux-thunk
允许派发函数,此函数被调用时接收 dispatchgetState 作为参数,作为 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 是 Redux 常用异步中间件(sagas 和 observables)的轻量替代方案。与 thunk 的复杂度和概念类似,可用于模拟一些常见 saga 使用模式。

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
使用看起来是同步的 generator 函数处理异步逻辑。Saga 返回效果描述,Saga 中间件执行这些效果,类似 JS 应用的“后台线程”。

适合:复杂异步逻辑,解耦流程

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 可观察者链(称为“epics”)处理异步逻辑。组合和取消异步动作以创建副作用等。

适合:复杂异步逻辑,解耦流程

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 架构移植到 Redux,通过从 reducer 返回副作用描述自然且纯粹地连续执行副作用。Reducer 现在返回状态和副作用描述两部分。

适合:尽可能在 Redux+JS 中模拟 Elm

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

基于 observables 的副作用库,也支持回调、promise、async/await、观察者。提供声明式的动作处理。

适合:高度解耦的异步逻辑

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)
}
})

Promises

acdlite/redux-promise
将 Promise 作为动作载荷派发,并在 Promise 解决或拒绝时派发 FSA 规范的动作。

dispatch({ type: 'FETCH_DATA', payload: myAjaxLib.get('/data') })
// 如果成功,将派发 {type : "FETCH_DATA", payload : response},
// 如果失败,将派发 {type : "FETCH_DATA", payload : error, error : true}

lelandrichardson/redux-pack
合理的、声明式、基于约定的 Promise 处理,引导用户走向好方式而不暴露全部 dispatch 威力。

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

// 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 }),
});

中间件

网络与 Socket

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 的动作防抖中间件

mathieudutour/redux-queue-offline
离线时排队动作,网络恢复时派发

分析

rangle/redux-beacon
支持任何分析服务,可离线跟踪,解耦分析逻辑与应用逻辑

markdalgleish/redux-analytics
监控带有 meta analytics 值的 Flux 标准动作,并进行处理

实体与集合

tommikaikkonen/redux-orm
用于管理 Redux store 中关系数据的简单不可变 ORM。

Versent/redux-crud
基于约定的 CRUD 逻辑动作和 reducer

kwelch/entities-reducer
处理 Normalizr 数据的高阶 reducer

amplitude/redux-query
在组件中声明共存的数据依赖,组件挂载时运行查询,实现乐观更新,并通过 Redux 动作触发服务器变更。

cantierecreativo/redux-bees
声明式 JSON-API 交互,支持数据标准化,带 React 高阶组件实现查询运行

GetAmbassador/redux-clerk
支持正规化、乐观更新、同步/异步动作创建器、选择器及可扩展 reducer 的异步 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
通过构建针对组件实例作用域的动作和 reducer,致力于让可复用组件更容易使用 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

Dan Abramov 的原始 Redux DevTools 实现,支持应用内状态显示和时间旅行调试

zalmoxisus/redux-devtools-extension

Mihail Diordiev 的浏览器扩展,捆绑多个状态监视视图,并与浏览器开发工具集成

infinitered/reactotron

跨平台 Electron 应用,用于检查 React 和 React Native 应用,包括应用状态、API 请求、性能、错误、sagas、动作派发。

DevTools 监视器

Log Monitor
Redux DevTools 的默认监视器,带有树形视图

Dock Monitor
Redux DevTools 监视器的可调整大小和可移动停靠窗口

Slider Monitor
Redux DevTools 的自定义监视器,用于重放记录的 Redux 动作

Diff Monitor
Redux DevTools 的监视器,比较动作间的 Redux store 变化

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
中间件,当尝试在 dispatch 内或 dispatch 之间修改状态时抛错

flexport/mutation-sentinel
帮助运行时深度检测变异并强制代码中不可变性

mmahalwy/redux-pure-connect
检查并记录 react-redux 的 connect 是否传入了产生不纯属性的 mapState 函数

测试

arnaudbenard/redux-mock-store
一个 mock store,保存已派发动作用于断言

Workable/redux-test-belt
扩展 store API,便于断言、隔离和操作 store

conorhastings/redux-test-recorder
中间件,根据应用中的动作自动生成 reducer 测试

wix/redux-testkit
用于测试 Redux 项目(reducer、选择器、动作、thunk)的完整且有指导的测试工具包

jfairbank/redux-saga-test-plan
让 saga 的集成和单元测试变得轻松

路由

supasate/connected-react-router 同步 React Router v4+ 状态与 Redux store。

faceyspacey/redux-first-router
无缝的 Redux 优先路由。将应用视为状态而非路由和组件,同时保持地址栏同步。所有一切皆为状态。连接组件,并只需派发 Flux 标准动作。

表单

erikras/redux-form
功能完善的库,使 React HTML 表单状态存储于 Redux。

davidkpiano/react-redux-form
React Redux Form 是一组 reducer 创建器和动作创建器,使得利用 React 和 Redux 实现复杂且自定义的表单既简单又高效。

更高级的抽象

keajs/kea
Redux、Redux-Saga 和 Reselect 之上的抽象,提供应用动作、reducer、选择器和 saga 的框架。赋能 Redux,使其使用如同 setState,减少模板代码和冗余,同时保持可组合性。

TheComfyChair/redux-scc
采用定义结构,并使用“行为”创建一套动作、reducer 响应和选择器。

Bloomca/redux-tiles
在 Redux 之上提供轻量抽象,方便组合,便于异步请求和合理的可测试性。

社区约定

Flux Standard Action
针对 Flux 动作对象的友好标准

Canonical Reducer Composition
针对嵌套 reducer 组合的主观标准

Ducks: Redux Reducer Bundles
关于把 reducer、动作类型和动作打包的提案