Redux
  • Read Me
  • Introduction
    • Motivation
    • Core Concepts
    • Three Principles
    • Prior Art
    • Learning Resources
    • Ecosystem
    • Examples
  • Basics
    • Actions
    • Reducers
    • Store
    • Data Flow
    • Usage with React
    • Example: Todo List
  • Advanced
    • Async Actions
    • Async Flow
    • Middleware
    • Usage with React Router
    • Example: Reddit API
    • Next Steps
  • Recipes
    • Configuring Your Store
    • Migrating to Redux
    • Using Object Spread Operator
    • Reducing Boilerplate
    • Server Rendering
    • Writing Tests
    • Computing Derived Data
    • Implementing Undo History
    • Isolating Subapps
    • Structuring Reducers
      • Prerequisite Concepts
      • Basic Reducer Structure
      • Splitting Reducer Logic
      • Refactoring Reducers Example
      • Using combineReducers
      • Beyond combineReducers
      • Normalizing State Shape
      • Updating Normalized Data
      • Reusing Reducer Logic
      • Immutable Update Patterns
      • Initializing State
    • Using Immutable.JS with Redux
  • FAQ
    • General
    • Reducers
    • Organizing State
    • Store Setup
    • Actions
    • Immutable Data
    • Code Structure
    • Performance
    • Design Decisions
    • React Redux
    • Miscellaneous
  • Troubleshooting
  • Glossary
  • API Reference
    • createStore
    • Store
    • combineReducers
    • applyMiddleware
    • bindActionCreators
    • compose
  • Change Log
  • Patrons
  • Feedback
Powered by GitBook
On this page
  • Table of Contents
  • Library Integration and Bindings
  • Reducers
  • Reducer Combination
  • Reducer Composition
  • Higher-Order Reducers
  • Actions
  • Utilities
  • Store
  • Change Subscriptions
  • Batching
  • Persistence
  • Immutable Data
  • Data Structures
  • Immutable Update Utilities
  • Immutable/Redux Interop
  • Side Effects
  • Widely Used
  • Promises
  • Middleware
  • Networks and Sockets
  • Async Behavior
  • Analytics
  • Entities and Collections
  • Component State and Encapsulation
  • Dev Tools
  • Debuggers and Viewers
  • DevTools Monitors
  • Logging
  • Mutation Detection
  • Testing
  • Routing
  • Forms
  • Higher-Level Abstractions
  • Community Conventions
  1. Introduction

Ecosystem

PreviousLearning ResourcesNextExamples

Last updated 7 years ago

Redux is a tiny library, but its contracts and APIs are carefully chosen to spawn an ecosystem of tools and extensions, and the community has created a wide variety of helpful addons, libraries, and tools. You don't need to use any of these addons to use Redux, but they can help make it easier to implement features and solve problems in your application.

For an extensive catalog of libraries, addons, and tools related to Redux, check out the list. Also, the list contains tutorials and other useful resources for anyone learning React or Redux.

This page lists some of the Redux-related addons that the Redux maintainers have vetted personally, or that have shown widespread adoption in the community. Don't let this discourage you from trying the rest of them! The ecosystem is growing too fast, and we have a limited time to look at everything. Consider these the “staff picks”, and don't hesitate to submit a PR if you've built something wonderful with Redux.

Table of Contents

Library Integration and Bindings

Reducers

Reducer Combination

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

Reducer Composition

const combinedReducer = combineReducers({ users, posts, comments })
const rootReducer = reduceReducers(combinedReducer, otherTopLevelFeatureReducer)
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
  )
const myCounter = counter({
  incrementActionTypes: ['INCREMENT'],
  decrementActionTypes: ['DECREMENT']
})

Higher-Order Reducers

Actions

const increment = createAction('INCREMENT')
const reducer = handleActions({ [increment]: (state, action) => state + 1 }, 0)
const store = createStore(reducer)
store.dispatch(increment())
export const types = createTypes(
  ['openModal', createAsyncTypes('fetch')],
  'app'
)
// { openModal : "app.openModal", fetch : { start : "app.fetch.start", complete: 'app.fetch.complete' } }
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', }

Utilities

const taxSelector = createSelector(
  [subtotalSelector, taxPercentSelector],
  (subtotal, taxPercent) => subtotal * (taxPercent / 100)
)
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)
const getBarBaz = createSelector(
  ['foo.bar', 'baz'],
  (bar, baz) => `${bar} ${baz}`
)
getBarBaz({ foo: { bar: 'a' }, baz: 'b' }) // "a b"

Store

Change Subscriptions

let w = watch(() => mySelector(store.getState()))
store.subscribe(
  w((newVal, oldVal) => {
    console.log(newval, oldVal)
  })
)
store.dispatch( subscribe("users.byId.abcd", "subscription1", () => {} );

Batching

const debounceNotify = _.debounce(notify => notify())
const store = createStore(
  reducer,
  initialState,
  batchedSubscribe(debounceNotify)
)
const store = createStore(reducer, reduxBatch)
store.dispatch([{ type: 'INCREMENT' }, { type: 'INCREMENT' }])
const store = createStore(reducer, initialState, batch().enhancer)
store.dispatch(createAction({ type: 'INCREMENT' }, { type: 'INCREMENT' }))
const store = createStore(enableBatching(reducer), initialState)
store.dispatch(batchActions([{ type: 'INCREMENT' }, { type: 'INCREMENT' }]))

Persistence

const store = createStore(reducer, autoRehydrate())
persistStore(store)
const reducer = storage.reducer(combineReducers(reducers))
const engine = createEngineLocalStorage('my-save-key')
const storageMiddleware = storage.createMiddleware(engine)
const store = createStore(reducer, applyMiddleware(storageMiddleware))
const store = createStore(reducer, offline(offlineConfig))
store.dispatch({
  type: 'FOLLOW_USER_REQUEST',
  meta: { offline: { effect: {}, commit: {}, rollback: {} } }
})

Immutable Data

Data Structures

const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50
const array = Immutable(['totally', 'immutable', { a: 42 }])
array[0] = 'edited' // does nothing
const foo = crio(['foo'])
const fooBar = foo.push('bar') // new array: ['foo', 'bar']
const newObj = icepick.assocIn({ c: { d: 'bar' } }, ['c', 'd'], 'baz')
const obj3 = icepicke.merge(obj1, obj2)

Immutable Update Utilities

const nextState = produce(baseState, draftState => {
  draftState.push({ todo: 'Tweet about it' })
  draftState[1].done = true
})
const newData = update(myData, {
  x: { y: { z: { $set: 7 } } },
  a: { b: { $push: [9] } }
})
const newObj = immutable(obj)
  .set('a.b', 'f')
  .del(['a', 'c', 0])
  .value()
const newState = dotProp.set(state, `todos.${index}.complete`, true)
const endOfArray = dotProp.get(obj, 'foo.$end')

Immutable/Redux Interop

const initialState = Immutable.Map()
const rootReducer = combineReducers({})
const store = createStore(rootReducer, initialState)
import { combineReducers } from 'redux-seamless-immutable';
const rootReducer = combineReducers({ userReducer, posts

Side Effects

Widely Used

Best for: getting started, simple async and complex synchronous logic.

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

Best for: complex async logic, decoupled workflows

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

Handle async logic using RxJS observable chains called "epics". Compose and cancel async actions to create side effects and more.

Best for: complex async logic, decoupled workflows

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)

A port of the Elm Architecture to Redux that allows you to sequence your effects naturally and purely by returning them from your reducers. Reducers now return both a state value and a side effect description.

Best for: trying to be as much like Elm as possible in 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
  }
}

Side effects lib built with observables, but allows use of callbacks, promises, async/await, or observables. Provides declarative processing of actions.

Best for: very decoupled async logic

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

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

Networks and Sockets

export const loadCategories() => ({ type: 'LOAD', payload: { request : { url: '/categories'} } });
const fetchUsers = () => ({
    endpoint: 'http://www.example.com/api/users',
    method: 'GET',
    types: ['REQUEST', 'SUCCESS', 'FAILURE']
  }
})
const store = createStore(reducer, applyMiddleware(socketIoMiddleware))
store.dispatch({ type: 'server/hello', data: 'Hello!' })

Async Behavior

Analytics

Entities and Collections

Component State and Encapsulation

@ui({
  key: 'some-name',
  state: { uiVar1: '', uiVar2: (props, state) => state.someValue },
  reducer: (state, action) => {}
})
class YourComponent extends React.Component {}
@local({
  ident: 'counter', initial: 0, reducer : (state, action) => action.me ? state + 1 : state }
})
class Counter extends React.Component {
const DynamicCounters = connectLean(
    scope: "dynamicCounters",
    getInitialState() => ({counterCount : 1}),
    addCounter, removeCounter
)(CounterList);
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 } }
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)

Dev Tools

Debuggers and Viewers

Dan Abramov's original Redux DevTools implementation, built for in-app display of state and time-travel debugging

Mihail Diordiev's browser extension, which bundles multiple state monitor views and adds integration with the browser's own dev tools

A cross-platform Electron app for inspecting React and React Native apps, including app state, API requests, perf, errors, sagas, and action dispatching.

DevTools Monitors

Logging

Mutation Detection

Testing

Routing

Forms

Higher-Level Abstractions

Community Conventions

The official React bindings for Redux, maintained by the Redux team

Angular 1 bindings for Redux

Angular 2+ bindings for Redux

Ember bindings for Redux

Redux bindings for Ember's Glimmer component engine

Redux bindings for Polymer

Redux bindings for custom elements

An expanded version of combineReducers, which allows passing state as a third argument to all slice reducers.

A combineReducers variation that allows defining cross-slice dependencies for ordering and data passing

Provides sequential composition of reducers at the same level

A collection of composable reducer transformers

Reducer factory functions for common data structures: counters, maps, lists (queues, stacks), sets

Effortless undo/redo and action history for your reducers

Ignore redux actions by array or filter function

Reset the redux state on certain actions

A reducer enhancer to enable type-agnostic optimistic updates

Flux Standard Action utilities for Redux

Creates standard and async action types based on namespaces

Generates action creators based on types and expected fields

Creates composable memoized selector functions for efficiently deriving data from the store state

Normalizes nested JSON according to a schema

Abstractions over Reselect for common selector use cases

Watch for state changes based on key paths or selectors

Centralized subscriptions to state changes based on paths

Store enhancer that can debounce subscription notifications

Store enhancer that allows dispatching arrays of actions

Store enhancer that accepts batched actions

Higher-order reducer that handles batched actions

Persist and rehydrate a Redux store, with many extensible options

Persistence layer for Redux with flexible backends

Persistent store for Offline-First apps, with support for optimistic UIs

Immutable persistent data collections for Javascript

Frozen immutable arrays/objects, backwards-compatible with JS

Immutable JS objects with a natural API

Utilities for treating frozen JS objects as persistent immutable collections.

Immutable updates with normal mutative code, using Proxies

A drop-in replacement for react-addons-update

Simpler alternative to immutability-helpers and Immutable.js

Immutable version of the dot-prop lib, with some extensions

combineReducers equivalent that works with Immutable.js Maps

combineReducers equivalent that works with seamless-immutable values

Dispatch functions, which are called and given dispatch and getState as parameters. This acts as a loophole for AJAX calls and other async behavior.

Handle async logic using synchronous-looking generator functions. Sagas return descriptions of effects, which are executed by the saga middleware, and act like "background threads" for JS applications.

Dispatch promises as action payloads, and have FSA-compliant actions dispatched as the promise resolves or rejects.

Sensible, declarative, convention-based promise handling that guides users in a good direction without exposing the full power of dispatch.

Fetches data with Axios and dispatches start/success/fail actions

Reads API call actions, fetches, and dispatches FSAs

An opinionated connector between socket.io and redux.

Integration between Firebase, React, and Redux

Buffers all actions into a queue until a breaker condition is met, at which point the queue is released

FSA-compliant middleware for Redux to debounce actions.

Queue actions when offline and dispatch them when getting back online.

Integrates with any analytics services, can track while offline, and decouples analytics logic from app logic

Analytics and tracking with an easy API for writing your own adapters

Watches for Flux Standard Actions with meta analytics values and processes them

A simple immutable ORM to manage relational data in your Redux store.

Convention-based actions and reducers for CRUD logic

A higher-order reducer that handles data from Normalizr

Declare colocated data dependencies with your components, run queries when components mount, perform optimistic updates, and trigger server changes with Redux actions.

Declarative JSON-API interaction that normalizes data, with a React HOC that can run queries

Async CRUD handling with normalization, optimistic updates, sync/async action creators, selectors, and an extendable reducer.

JSON-API abstraction with async CRUD, normalization, optimistic updates, caching, data status, and error handling.

A tiny but powerful system for managing 'resources': data that is persisted to remote servers.

"Block-level scoping" for UI state. Decorated components declare data fields, which become props and can be updated by nested children.

Local component state in Redux, with handling for component actions

Makes component state in Redux as easy as setState

Creates isolated "sub-stores" for decoupled micro front-ends, with integration for React, sagas, and observables

Aims to make reusable components easier to build with Redux by scoping actions and reducers to a particular instance of a component.

The default monitor for Redux DevTools with a tree view

A resizable and movable dock for Redux DevTools monitors

A custom monitor for Redux DevTools to replay recorded Redux actions

A custom monitor for Redux DevTools that lets you filter actions, inspect diffs, and pin deep paths in the state to observe their changes

A monitor for Redux DevTools that diffs the Redux store mutations between actions

Filterable tree view monitor for Redux DevTools

A chart monitor for Redux DevTools

Redux DevTools composable monitor with the ability to filter actions

Logging middleware that shows actions, states, and diffs

Enhancer that provides time-travel and efficient action recording capabilities, including import/export of action logs and action playback.

Record and replay user sessions in real-time

Warns about actions that produced no state changes in development

Middleware that throws an error when you try to mutate your state either inside a dispatch or between dispatches.

Helps you deeply detect mutations at runtime and enforce immutability in your codebase.

Check and log whether react-redux's connect method is passed mapState functions that create impure props.

A mock store that saves dispatched actions in an array for assertions

Extends the store API to make it easier assert, isolate, and manipulate the store

Middleware to automatically generate reducers tests based on actions in the app

Complete and opinionated testkit for testing Redux projects (reducers, selectors, actions, thunks)

Makes integration and unit testing of sagas a breeze

Synchronize React Router 4 state with your Redux store.

A tiny router for Redux applications that lets the URL do the talking

Seamless Redux-first routing. Think of your app in states, not routes, not components, while keeping the address bar in sync. Everything is state. Connect your components and just dispatch flux standard actions.

A full-featured library to enable a React HTML form to store its state in Redux.

React Redux Form is a collection of reducer creators and action creators that make implementing even the most complex and custom forms with React and Redux simple and performant.

An abstraction over Redux, Redux-Saga and Reselect. Provides a framework for your app’s actions, reducers, selectors and sagas. It empowers Redux, making it as simple to use as setState. It reduces boilerplate and redundancy, while retaining composability.

A simplified layer over Redux. No action creators or explicit dispatching, with a built-in simple side effects system.

Takes a defined structure and uses 'behaviors' to create a set of actions, reducer responses and selectors.

Provides minimal abstraction on top of Redux, to allow easy composability, easy async requests, and sane testability.

A human-friendly standard for Flux action objects

An opinionated standard for nested reducer composition

A proposal for bundling reducers, action types and actions

reduxjs/react-redux
angular-redux/ng-redux
angular-redux/store
ember-redux/ember-redux
glimmer-redux/glimmer-redux
tur-nr/polymer-redux
lastmjs/redux-store-element
ryo33/combineSectionReducers
KodersLab/topologically-combine-reducers
acdlite/reduce-reducers
mhelmer/redux-xforms
adrienjt/redux-data-structures
omnidan/redux-undo
omnidan/redux-ignore
omnidan/redux-recycle
ForbesLindesay/redux-optimist
reduxactions/redux-actions
BerkeleyTrue/redux-create-types
maxhallinan/kreighter
reduxjs/reselect
paularmstrong/normalizr
planttheidea/selectorator
jprichardson/redux-watch
ashaffer/redux-subscribe
tappleby/redux-batched-subscribe
manaflair/redux-batch
laysent/redux-batch-actions-enhancer
tshelburne/redux-batched-actions
rt2zz/redux-persist
react-stack/redux-storage
redux-offline/redux-offline
facebook/immutable-js
rtfeldman/seamless-immutable
planttheidea/crio
aearly/icepick
mweststrate/immer
kolodny/immutability-helper
mariocasciaro/object-path-immutable
debitoor/dot-prop-immutable
gajus/redux-immutable
eadmundo/redux-seamless-immutable
gaearon/redux-thunk
redux-saga/redux-saga
redux-observable/redux-observable
redux-loop/redux-loop
jeffbski/redux-logic
acdlite/redux-promise
lelandrichardson/redux-pack
svrcekmichal/redux-axios-middleware
agraboso/redux-api-middleware
itaylor/redux-socket.io
tiberiuc/redux-react-firebase
rt2zz/redux-action-buffer
wyze/redux-debounce
mathieudutour/redux-queue-offline
rangle/redux-beacon
hyperlab/redux-insights
markdalgleish/redux-analytics
tommikaikkonen/redux-orm
Versent/redux-crud
kwelch/entities-reducer
amplitude/redux-query
cantierecreativo/redux-bees
GetAmbassador/redux-clerk
shoutem/redux-io
jmeas/redux-resource
tonyhb/redux-ui
threepointone/redux-react-local
epeli/lean-redux
ioof-holdings/redux-subspace
DataDog/redux-doghouse
reduxjs/redux-devtools
zalmoxisus/redux-devtools-extension
infinitered/reactotron
Log Monitor
Dock Monitor
Slider Monitor
Inspector
Diff Monitor
Filterable Log Monitor
Chart Monitor
Filter Actions
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
arnaudbenard/redux-mock-store
Workable/redux-test-belt
conorhastings/redux-test-recorder
wix/redux-testkit
jfairbank/redux-saga-test-plan
supasate/connected-react-router
FormidableLabs/redux-little-router
faceyspacey/redux-first-router
erikras/redux-form
davidkpiano/react-redux-form
keajs/kea
jumpsuit/jumpstate
TheComfyChair/redux-scc
Bloomca/redux-tiles
Flux Standard Action
Canonical Reducer Composition
Ducks: Redux Reducer Bundles
Redux Ecosystem Links
React/Redux Links
Library Integration and Bindings
Reducers
Reducer Combination
Reducer Composition
Higher-Order Reducers
Actions
Utilities
Store
Change Subscriptions
Batching
Persistence
Immutable Data
Data Structures
Immutable Update Utilities
Immutable/Redux Interop
Side Effects
Widely Used
Promises
Middleware
Networks and Sockets
Async Behavior
Analytics
Entities and Collections
Component State and Encapsulation
Dev Tools
Debuggers and Viewers
DevTools Monitors
Logging
Mutation Detection
Testing
Routing
Forms
Higher-Level Abstractions
Community Conventions