生态系统

Redux 是一个体小精悍的库,但它相关的内容和 API 都是精挑细选的,目的是衍生出丰富的工具集和可扩展的生态系统。社区已经创建了各种各样的有用的插件、库和工具。使用 Redux 时并不需要您非要使用这些插件,但是它们可以帮助您更容易地实现特性并解决应用程序中的问题。

如果需要关于 Redux 所有内容的列表,推荐移步至 Awesome Redux。它包含了示例、样板代码、中间件、工具库,还有很多其它相关内容。要想学习 React 和 Redux ,React/Redux Links 包含了教程和不少有用的资源,Redux Ecosystem Links 则列出了 许多 Redux 相关的库及插件。

本页将只列出由 Redux 维护者审查过的一部分内容。不要因此打消尝试其它工具的信心!整个生态发展得太快,我们没有足够的时间去关注所有内容。建议只把这些当作“内部推荐”,如果你使用 Redux 创建了很酷的内容,不要犹豫,马上发个 PR 吧。

目录

与不同框架绑定

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

angular-redux/ng-redux
Redux 与 Angular 1 的绑定库

angular-redux/store
Redux 与 Angular 2+ 的绑定库

ember-redux/ember-redux
Redux 与 Ember 的绑定库

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

tur-nr/polymer-redux
Redux 与 Polymer 的绑定库

lastmjs/redux-store-element Redux 与自定义组件的绑定库

Reducers

组合 Reducer

ryo33/combineSectionReducers
combineReducers 的扩展版本,它允许将 state 作为第三个参数传递给所有的子 reducer。

KodersLab/topologically-combine-reducers
一种 combineReducers 变体,定义 reducer 之间的相互依赖用于调用排序和数据传递

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({}), // 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
Reducer 工厂函数,用于常见数据结构:计数器,映射,列表(队列,堆栈),集合

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

高阶 Reducers

omnidan/redux-undo
轻松为 reducer 实现 undo/redo 和 action 的历史记录功能。

omnidan/redux-ignore
通过数组或过滤器函数忽略 redux action

omnidan/redux-recycle
在某些 action 上重置 redux 状态

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

Actions

reduxactions/redux-actions
Redux 的 Flux 标准 action 实用程序。

const increment = createAction('INCREMENT')
const reducer = handleActions({ [increment]: (state, action) => state + 1 }, 0)
const store = createStore(reducer)
store.dispatch(increment())

BerkeleyTrue/redux-create-types
根据命名空间创建标准和异步 action type。

export const types = createTypes(
  ['openModal', createAsyncTypes('fetch')],
  'app'
)
// { openModal : "app.openModal", fetch : { start : "app.fetch.start", complete: 'app.fetch.complete' } }

maxhallinan/kreighter
根据类型和预期字段生成 action creator

const formatTitle = (id, title) => ({
  id,
  title: toTitleCase(title)
})
const updateBazTitle = fromType('UPDATE_BAZ_TITLE', formatTitle)
updateBazTitle(1, 'foo bar baz')
// -> { type: 'UPDATE_BAZ_TITLE', id: 1, title: 'Foo Bar Baz', }

工具集

reduxjs/reselect
创建可组合的 memoized 选择器函数,以便从 store state 有效地导出数据

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
对于常见 selector 用例的 reselect 的抽象化

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

Store

更改订阅

jprichardson/redux-watch
根据 key path 或 selector 监视状态更改

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

ashaffer/redux-subscribe
集中订阅基于 path 的 state 更改

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

批处理

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

const debounceNotify = _.debounce(notify => notify())
const store = createStore(
  reducer,
  initialState,
  batchedSubscribe(debounceNotify)
)

manaflair/redux-batch
store 增强器,允许 dispatch action 数组

const store = createStore(reducer, reduxBatch)
store.dispatch([{ type: 'INCREMENT' }, { type: 'INCREMENT' }])

laysent/redux-batch-actions-enhancer
store 增强器,接受批量 action

const store = createStore(reducer, initialState, batch().enhancer)
store.dispatch(createAction({ type: 'INCREMENT' }, { type: 'INCREMENT' }))

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

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

持久化

rt2zz/redux-persist
使用许多可扩展的选项,持久化和补充 Redux store。

const store = createStore(reducer, autoRehydrate())
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 = createStore(reducer, applyMiddleware(storageMiddleware))

redux-offline/redux-offline
用于 Offline-First 应用程序的持久 store ,支持积极的 UI 更新(optimistic UI)

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

不可变(Immutable)数据

数据结构

facebook/immutable-js
Javascript 的不可变持久数据集合

const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50

rtfeldman/seamless-immutable
冻结的不可变数组/对象,向后兼容 JS

const array = Immutable(['totally', 'immutable', { a: 42 }])
array[0] = 'edited' // does nothing

planttheidea/crio
具有 API 的不可变 JS 对象

const foo = crio(['foo'])
const fooBar = foo.push('bar') // new array: ['foo', 'bar']

aearly/icepick
用于将冻结的 JS 对象视为持久不可变集合的实用程序。

const newObj = icepick.assocIn({ c: { d: 'bar' } }, ['c', 'd'], 'baz')
const obj3 = icepicke.merge(obj1, obj2)

不可变更新(Immutable Update)实用程序

mweststrate/immer
运用代理使用普通的更新代码进行不可变更新

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

kolodny/immutability-helper
react-addons-update 的直接替代品

const newData = update(myData, {
  x: { y: { z: { $set: 7 } } },
  a: { b: { $push: [9] } }
})

mariocasciaro/object-path-immutable
更简单的替代 immutability-helpers 和 Immutable.js 的库

const newObj = immutable(obj)
  .set('a.b', 'f')
  .del(['a', 'c', 0])
  .value()

debitoor/dot-prop-immutable
dot-prop 库的不可变(Immutable)版本,带有一些扩展

const newState = dotProp.set(state, `todos.${index}.complete`, true)
const endOfArray = dotProp.get(obj, 'foo.$end')

Immutable/Redux 互操作

gajus/redux-immutable
与 Immutable.js Maps 一起使用的 combineReducers 等价物

const initialState = Immutable.Map()
const rootReducer = combineReducers({})
const store = createStore(rootReducer, initialState)

eadmundo/redux-seamless-immutable
与 combineReducers 等效,与 seamless-immutable value 一起使用

import { combineReducers } from 'redux-seamless-immutable';
const rootReducer = combineReducers({ userReducer, posts

副作用(Side Effects)

广泛使用

gaearon/redux-thunk
调度(dispatch)函数,调用并将 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});
        }
    }
}

redux-saga/redux-saga
使用同步查找生成器函数处理异步逻辑。 Sagas 返回 effect 的描述, 这些 effect 由 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

使用称为 “epics” 的 RxJS 可观察链处理异步逻辑。 撰写和取消异步操作以创建副作用等。

适用于: 复杂的异步逻辑,解耦的工作流程

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 返回它们来自然而纯粹地对您的 effect 进行排序。 reducer 现在返回状态值和副作用描述。

适用于: 试图尽可能地像 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 构建的副作用 lib,但允许使用回调、promises、async/await 或 observables。 提供 action 的声明性处理。

适用于: 非常分离的异步逻辑

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
调度(Dispatch) promise 作为 action 的有效负载,并在 promise resolve 或 reject 时调度 FSA 兼容(FSA-compliant)的 action 。

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
明智的、声明性的、基于约定的处理 promise,可以指导用户朝着良好的方向发展而不会暴露出全部的调度(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 }),
            });

中间件

Networks and Sockets

svrcekmichal/redux-axios-middleware
使用 Axios 获取数据并调度(dispatch)启动 / 成功 / 失败 action。

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

agraboso/redux-api-middleware
通过读取 API 调用 action、获取数据和调度 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 = createStore(reducer, applyMiddleware(socketIoMiddleware))
store.dispatch({ type: 'server/hello', data: 'Hello!' })

tiberiuc/redux-react-firebase
Firebase、React 和 Redux 之间的集成。

异步行为

rt2zz/redux-action-buffer
将所有操作缓冲到队列中,直到满足断路器条件,此时释放队列

wyze/redux-debounce
符合 FSA 标准的 Redux 中间件可以实现 action 的防抖。

mathieudutour/redux-queue-offline
离线时将 action 加入队列,并在重新联机时 dispatch 它们。

分析

rangle/redux-beacon
与任何分析服务集成,可以在离线时跟踪,并将分析逻辑与应用逻辑分离。

hyperlab/redux-insights
使用简单的 API 进行分析和跟踪,以编写自己的适配器

markdalgleish/redux-analytics
使用 meta 分析值监视 Flux 标准操作并处理它们

实体和集合

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

Versent/redux-crud
基于约定的 action 和 reducer,用于处理 CRUD 逻辑

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

amplitude/redux-query
声明与组件共存的数据依赖关系,在组件 mount 时运行查询、执行乐观更新以及使用 Redux action 触发服务器更改。

cantierecreativo/redux-bees
声明性 JSON-API 交互,用于规范化数据,与可以运行查询的 React 高阶组件(HOC)交互

GetAmbassador/redux-clerk
具有规范化、乐观更新、同步/异步 action creator、 selector 和可扩展 reducer 的异步 CRUD 处理。

shoutem/redux-io
具有异步 CRUD、规范化、乐观更新、缓存、数据状态和错误处理的 JSON-API 抽象。

jmeas/redux-resource
用于管理“资源”的小而强大的系统:持久存储到远程服务器的数据。

组件 state 和封装

tonyhb/redux-ui
用于 UI state 的“块级范围”。 装饰组件以声明数据字段,使这些数据字段成为 props 并可由嵌套子项更新。

@ui({
  key: 'some-name',
  state: { uiVar1: '', uiVar2: (props, state) => state.someValue },
  reducer: (state, action) => {}
})
class YourComponent extends React.Component {}

threepointone/redux-react-local
Redux 中的本地组件 state,用于处理组件 action

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

epeli/lean-redux
使 Redux 中的组件的 state 与 setState 一样简单

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

ioof-holdings/redux-subspace
为分离的微前端创建独立的 “sub-store”,集成了 React、sagas 和 observables

const reducer = combineReducers({
  subApp1: namespaced('subApp1')(counter),
  subApp2: namespaced('subApp2')(counter)
})

const subApp1Store = subspace(state => state.subApp1, 'subApp1')(store)
const subApp2Store = subspace(state => state.subApp2, 'subApp2')(store)

subApp1Store.dispatch({ type: 'INCREMENT' })
console.log('store state:', store.getState()) // { "subApp1": { value: 2 }, "subApp2": { value: 1 } }

DataDog/redux-doghouse
旨在通过将 actIon 和 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)

开发者工具

Debuggers and Viewers

reduxjs/redux-devtools

Dan Abramov 最初的 Redux DevTools 实现,专为在应用程序内显示 state 和 time-travel 调试而构建

zalmoxisus/redux-devtools-extension

Mihail Diordiev 的浏览器扩展,捆绑了多个 state 监视器视图,并增加了与浏览器自己的开发工具的集成

infinitered/reactotron

用于检查 React 和 React Native 应用程序的跨平台 Electron 应用程序,包括应用程序状态、API 请求、性能、错误、saga 和操作调度。

开发者工具监视器

Log Monitor
Redux DevTools 默认监视器,提供树状视图

Dock Monitor
Redux DevTools 监视器的可调整大小和可移动的底座

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

Inspector
Redux DevTools 的自定义监视器,可让您过滤操作,检查差异,并在状态中固定深层路径以观察其更改

Diff Monitor
Redux DevTools 的监视器,用于在 action 之间区分 Redux store 突变

Filterable Log Monitor
树状可筛选视图的 Redux DevTools 监视器

Chart Monitor
Redux DevTools 的图表监视器

Filter Actions
Redux DevTools 可组合监视器,具有过滤 action 的能力

日志

evgenyrodionov/redux-logger
记录显示 action、state 和差异的中间件

inakianduaga/redux-state-history
提供 time-travel 和高效的 action 录制功能,包括导入 / 导出 action 日志和 action 播放的增强器。

joshwcomeau/redux-vcr
实时记录和重播用户会话

socialtables/redux-unhandled-action
在开发中对改变 state 的 action 发出警告

突变检测

leoasis/redux-immutable-state-invariant
当您尝试在调度(dispatch)内或调度(dispatch)之间改变状态时抛出错误的中间件。

flexport/mutation-sentinel
帮助您在运行时深入检测突变并在代码库中强制实现不变性(immutability)。

mmahalwy/redux-pure-connect
检查并记录 react-redux 的 connect 方法是否通过 mapState 函数创建了不纯的 props。

测试

arnaudbenard/redux-mock-store
一个模拟 store,用于将 dispatched action 保存在数组中以进行断言

Workable/redux-test-belt
扩展 store API 以使其更容易断言、隔离和操纵 store

conorhastings/redux-test-recorder
根据应用程序中的操作自动生成 Reducer 测试的中间件

wix/redux-testkit
用于测试 Redux 项目的完整且固定的测试工具包(Reducer、selectors、actions、thunk)

jfairbank/redux-saga-test-plan
使 saga 的集成和单元测试变得轻而易举

路由

ReactTraining/react-router-redux
保持 state 与路由同步

FormidableLabs/redux-little-router
Redux 应用程序的一个小型路由,可以与 URL 进行通信

faceyspacey/redux-first-router
无缝 Redux-first 路由。 在 state 中考虑您的应用,而不是在路由或组件中,同时保持与地址栏同步。 一切都是 state。 连接您的组件,只需调度(dispatch)标准的 action。

Forms

erikras/redux-form
一个功能齐全的库,可以使 React HTML 表单在 Redux 中存储其状态。

davidkpiano/react-redux-form
React Redux Form 是一个 reducer creator 和 action creator 的集合,它们使 React 和 Redux 可以简单而高效地实现最复杂和自定义的 form。

更高级别的抽象

keajs/kea
Redux、Redux-Saga 和 Reselect 的抽象。 为您的应用程序的 action、reducer、selector 和 saga 提供框架。 它赋予 Redux 权限,使其与 setState 一样简单。 它减少了样板和冗余,同时保持了可组合性。

jumpsuit/jumpstate
基于 Redux 的简化版本。 没有 action creator 或显式调度(dispatch),具有内置的简单副作用(side effect)系统。

TheComfyChair/redux-scc
采用定义的结构并使用“行为”来创建一组 actions、reducer responses 和 selectors。

Bloomca/redux-tiles
在 Redux 之上提供最小的抽象,以实现轻松的可组合性、简单的异步请求和可靠的可测试性。

社区公约

Flux Standard Action
Flux action object 的人性化标准

Canonical Reducer Composition
嵌套 reducer 组合的固定标准

Ducks: Redux Reducer Bundles
捆绑 reducer、action type 和 action 的提议