Redux
Redux
Table of Contents
1. Read Me
2. Introduction
i. Motivation
ii. Three Principles
iii. Prior Art
iv. Ecosystem
v. Examples
3. Basics
i. Actions
ii. Reducers
iii. Store
iv. Data Flow
v. Usage with React
vi. Example: Todo List
4. Advanced
i. Async Actions
ii. Async Flow
iii. Middleware
iv. Usage with React Router
v. Example: Reddit API
vi. Next Steps
5. Recipes
i. Migrating to Redux
ii. Reducing Boilerplate
iii. Server Rendering
iv. Writing Tests
v. Computing Derived Data
vi. Implementing Undo History
6. Troubleshooting
7. Glossary
8. API Reference
i. createStore
ii. Store
iii. combineReducers
iv. applyMiddleware
v. bindActionCreators
2
redux
vi. compose
9. Change Log
10. Patrons
3
redux
Redux
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client,
server, and native), and are easy to test. On top of that, it provides a great developer
experience, such as live code editing combined with a time traveling debugger.
You can use Redux together with React, or with any other view library.
It is tiny (2kB) and has no dependencies.
Testimonials
“Love what you’re doing with Redux”
Jing Chen, creator of Flux
“I asked for comments on Redux in FB's internal JS discussion group, and it was
universally praised. Really awesome work.”
Bill Fisher, author of Flux documentation
“It's cool that you are inventing a better Flux by not doing Flux at all.”
André Staltz, creator of Cycle
Developer Experience
I wrote Redux while working on my React Europe talk called “Hot Reloading with Time
Travel”. My goal was to create a state management library with minimal API but completely
predictable behavior, so it is possible to implement logging, hot reloading, time travel,
universal apps, record and replay, without any buy-in from the developer.
Influences
Redux evolves the ideas of Flux, but avoids its complexity by taking cues from Elm.
Whether you have used them or not, Redux only takes a few minutes to get started with.
Read Me 4
redux
Installation
To install the stable version:
Most likely, you’ll also need the React bindings and the developer tools.
This assumes that you’re using npm package manager with a module bundler like Webpack
or Browserify to consume CommonJS modules.
If you don’t yet use npm or a modern module bundler, and would rather prefer a single-file
UMD build that makes Redux available as a global object, you can grab a pre-built version
from cdnjs. We don’t recommend this approach for any serious application, as most of the
libraries complementary to Redux are only available on npm.
The Gist
The whole state of your app is stored in an object tree inside a single store.
The only way to change the state tree is to emit an action, an object describing what
happened.
To specify how the actions transform the state tree, you write pure reducers.
That’s it!
/**
* This is a reducer, a pure function with (state, action) => state signature.
* It describes how an action transforms the state into the next state.
*
* The shape of the state is up to you: it can be a primitive, an array, an object,
* or even an Immutable.js data structure. The only important part is that you should
* not mutate the state object, but return a new object if the state changes.
*
* In this example, we use a `switch` statement and strings, but you can use a helper that
* follows a different convention (such as function maps) if it makes sense for your project.
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
Read Me 5
redux
default:
return state
}
}
// You can subscribe to the updates manually, or use bindings to your view layer.
store.subscribe(() =>
console.log(store.getState())
)
Instead of mutating the state directly, you specify the mutations you want to happen with
plain objects called actions. Then you write a special function called a reducer to decide how
every action transforms the entire application’s state.
If you’re coming from Flux, there is a single important difference you need to understand.
Redux doesn’t have a Dispatcher or support many stores. Instead, there is just a single store
with a single root reducing function. As your app grows, instead of adding stores, you split
the root reducer into smaller reducers independently operating on the different parts of the
state tree. This is exactly like there is just one root component in a React app, but it is
composed out of many small components.
This architecture might seem like an overkill for a counter app, but the beauty of this pattern
is how well it scales to large and complex apps. It also enables very powerful developer
tools, because it is possible to trace every mutation to the action that caused it. You can
record user sessions and reproduce them just by replaying every action.
Read Me 6
redux
use #redux, it also shows how and why redux was built!”
Sandrino Di Mattia
“Plowing through @dan_abramov 'Getting Started with Redux' - its amazing how much
simpler concepts get with video.”
Chris Dhanaraj
“Come for the name hype. Stay for the rock solid fundamentals. (Thanks, and great job
@dan_abramov and @eggheadio!)”
Dan
Documentation
Introduction
Basics
Advanced
Recipes
Troubleshooting
Glossary
API Reference
For PDF, ePub, and MOBI exports for offline reading, and instructions on how to create
them, please see: paulkogel/redux-offline-docs.
Examples
Read Me 7
redux
Counter (source)
TodoMVC (source)
Todos with Undo (source)
Async (source)
Universal (source)
Real World (source)
Shopping Cart (source)
If you’re new to the NPM ecosystem and have troubles getting a project up and running, or
aren’t sure where to paste the gist above, check out simplest-redux-example that uses
Redux together with React and Browserify.
Discussion
Join the #redux channel of the Reactiflux Discord community.
Thanks
The Elm Architecture for a great intro to modeling state updates with reducers;
Turning the database inside-out for blowing my mind;
Developing ClojureScript with Figwheel for convincing me that re-evaluation should “just
work”;
Webpack for Hot Module Replacement;
Flummox for teaching me to approach Flux without boilerplate or singletons;
disto for a proof of concept of hot reloadable Stores;
NuclearJS for proving this architecture can be performant;
Om for popularizing the idea of a single state atom;
Cycle for showing how often a function is the best tool;
React for the pragmatic innovation.
Special thanks to Jamie Paton for handing over the redux NPM package name.
Change Log
This project adheres to Semantic Versioning.
Every release, along with the migration instructions, is documented on the Github Releases
page.
Patrons
The work on Redux was funded by the community.
Meet some of the outstanding companies that made it possible:
Read Me 8
redux
Webflow
Chess iX
License
MIT
Read Me 9
redux
Introduction
Motivation
Three Principles
Prior Art
Ecosystem
Examples
Introduction 10
redux
Motivation
As the requirements for JavaScript single-page applications have become increasingly
complicated, our code must manage more state than ever before. This state can include
server responses and cached data, as well as locally created data that has not yet been
persisted to the server. UI state is also increasing in complexity, as we need to manage the
active route, the selected tab, whether to show a spinner or not, should pagination controls
be displayed, and so on.
Managing this ever-changing state is hard. If a model can update another model, then a
view can update a model, which updates another model, and this, in turn, might cause
another view to update. At some point, you no longer understand what happens in your app
as you have lost control over the when, why, and how of its state. When a system is
opaque and non-deterministic, it’s hard to reproduce bugs or add new features.
As if this wasn’t bad enough, consider the new requirements becoming common in front-
end product development. As developers, we are expected to handle optimistic updates,
server-side rendering, fetching data before performing route transitions, and so on. We find
ourselves trying to manage a complexity that we have never had to deal with before, and we
inevitably ask the question: is it time to give up? The answer is no.
This complexity is difficult to handle as we’re mixing two concepts that are very hard for
the human mind to reason about: mutation and asynchronicity. I call them Mentos and
Coke. Both can be great in separation, but together they create a mess. Libraries like React
attempt to solve this problem in the view layer by removing both asynchrony and direct DOM
manipulation. However, managing the state of your data is left up to you. This is where
Redux enters.
Following in the steps of Flux, CQRS, and Event Sourcing, Redux attempts to make state
mutations predictable by imposing certain restrictions on how and when updates can
happen. These restrictions are reflected in the three principles of Redux.
Motivation 11
redux
Three Principles
Redux can be described in three fundamental principles:
This makes it easy to create universal apps, as the state from your server can be serialized
and hydrated into the client with no extra coding effort. A single state tree also makes it
easier to debug or introspect an application; it also enables you to persist your app’s state in
development, for a faster development cycle. Some functionality which has been traditionally
difficult to implement - Undo/Redo, for example - can suddenly become trivial to implement,
if all of your state is stored in a single tree.
console.log(store.getState())
/* Prints
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
*/
State is read-only
The only way to mutate the state is to emit an action, an object describing what
happened.
This ensures that neither the views nor the network callbacks will ever write directly to the
state. Instead, they express an intent to mutate. Because all mutations are centralized and
happen one by one in a strict order, there are no subtle race conditions to watch out for. As
actions are just plain objects, they can be logged, serialized, stored, and later replayed for
debugging or testing purposes.
Three Principles 12
redux
store.dispatch({
type: 'COMPLETE_TODO',
index: 1
})
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: 'SHOW_COMPLETED'
})
Reducers are just pure functions that take the previous state and an action, and return the
next state. Remember to return new state objects, instead of mutating the previous state.
You can start with a single reducer, and as your app grows, split it off into smaller reducers
that manage specific parts of the state tree. Because reducers are just functions, you can
control the order in which they are called, pass additional data, or even make reusable
reducers for common tasks such as pagination.
Three Principles 13
redux
Three Principles 14
redux
Prior Art
Redux has a mixed heritage. It is similar to some patterns and technologies, but is also
different from them in important ways. We’ll explore some of the similarities and the
differences below.
Flux
Can Redux be considered a Flux implementation?
Yes, and no.
(Don’t worry, Flux creators approve of it, if that’s all you wanted to know.)
Redux was inspired by several important qualities of Flux. Like Flux, Redux prescribes that
you concentrate your model update logic in a certain layer of your application (“stores” in
Flux, “reducers” in Redux). Instead of letting the application code directly mutate the data,
both tell you to describe every mutation as a plain object called an “action”.
Unlike Flux, Redux does not have the concept of a Dispatcher. This is because it relies
on pure functions instead of event emitters, and pure functions are easy to compose and
don’t need an additional entity managing them. Depending on how you view Flux, you may
see this as either a deviation or an implementation detail. Flux has often been described as
(state, action) => state . In this sense, Redux is true to the Flux architecture, but makes it
Another important difference from Flux is that Redux assumes you never mutate your
data. You can use plain objects and arrays for your state just fine, but mutating them inside
the reducers is strongly discouraged. You should always return a new object, which is easy
with the object spread syntax proposed for ES7 and implemented in Babel, or with a library
like Immutable.
While it is technically possible to write impure reducers that mutate the data for performance
corner cases, we actively discourage you from doing this. Development features like time
travel, record/replay, or hot reloading will break. Moreover it doesn’t seem like immutability
poses performance problems in most real apps, because, as Om demonstrates, even if you
lose out on object allocation, you still win by avoiding expensive re-renders and re-
calculations, as you know exactly what changed thanks to reducer purity.
Elm
Prior Art 15
redux
Unlike Redux, Elm is a language, so it is able to benefit from many things like enforced
purity, static typing, out of the box immutability, and pattern matching (using the case
expression). Even if you don’t plan to use Elm, you should read about the Elm architecture,
and play with it. There is an interesting JavaScript library playground implementing similar
ideas. We should look there for inspiration on Redux! One way that we can get closer to the
static typing of Elm is by using a gradual typing solution like Flow.
Immutable
Immutable is a JavaScript library implementing persistent data structures. It is performant
and has an idiomatic JavaScript API.
Immutable and most similar libraries are orthogonal to Redux. Feel free to use them
together!
Redux doesn’t care how you store the state—it can be a plain object, an Immutable
object, or anything else. You’ll probably want a (de)serialization mechanism for writing
universal apps and hydrating their state from the server, but other than that, you can use any
data storage library as long as it supports immutability. For example, it doesn’t make sense
to use Backbone for Redux state, because Backbone models are mutable.
Note that, even if your immutable library supports cursors, you shouldn’t use them in a
Redux app. The whole state tree should be considered read-only, and you should use
Redux for updating the state, and subscribing to the updates. Therefore writing via cursor
doesn’t make sense for Redux. If your only use case for cursors is decoupling the state
tree from the UI tree and gradually refining the cursors, you should look at selectors
instead. Selectors are composable getter functions. See reselect for a really great and
concise implementation of composable selectors.
Baobab
Baobab is another popular library implementing immutable API for updating plain JavaScript
objects. While you can use it with Redux, there is little benefit in using them together.
Most of the functionality Baobab provides is related to updating the data with cursors, but
Redux enforces that the only way to update the data is to dispatch an action. Therefore they
solve the same problem differently, and don’t complement each other.
Prior Art 16
redux
Unlike Immutable, Baobab doesn’t yet implement any special efficient data structures under
the hood, so you don’t really win anything from using it together with Redux. It’s easier to
just use plain objects in this case.
Rx
Reactive Extensions (and their undergoing modern rewrite) are a superb way to manage the
complexity of asynchronous apps. In fact there is an effort to create a library that models
human-computer interaction as interdependent observables.
Does it make sense to use Redux together with Rx? Sure! They work great together. For
example, it is easy to expose a Redux store as an observable:
function toObservable(store) {
return {
subscribe({ onNext }) {
let dispose = store.subscribe(() => onNext(store.getState()))
onNext(store.getState())
return { dispose }
}
}
}
Similarly, you can compose different asynchronous streams to turn them into actions before
feeding them to store.dispatch() .
The question is: do you really need Redux if you already use Rx? Maybe not. It’s not hard to
re-implement Redux in Rx. Some say it’s a two-liner using Rx .scan() method. It may very
well be!
If you’re in doubt, check out the Redux source code (there isn’t much going on there), as
well as its ecosystem (for example, the developer tools). If you don’t care too much about it
and want to go with the reactive data flow all the way, you might want to explore something
like Cycle instead, or even combine it with Redux. Let us know how it goes!
Prior Art 17
redux
Ecosystem
Redux is a tiny library, but its contracts and APIs are carefully chosen to spawn an
ecosystem of tools and extensions.
On this page we will only feature a few of them that the Redux maintainers have vetted
personally. 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.
Learning Redux
Screencasts
Getting Started with Redux — Learn the basics of Redux directly from its creator (30
free videos)
Example Apps
SoundRedux — A SoundCloud client built with Redux
Shopping Cart (Flux Comparison) — A shopping cart example from Flux Comparison
Ecosystem 18
redux
Talks
Live React: Hot Reloading and Time Travel — See how constraints enforced by Redux
make hot reloading with time travel easy
Cleaning the Tar: Using React within the Firefox Developer Tools — Learn how to
gradually migrate existing MVC applications to Redux
Redux: Simplifying Application State — An intro to Redux architecture
Using Redux
Bindings
react-redux — React
ng-redux — Angular
ng2-redux — Angular 2
backbone-redux — Backbone
redux-falcor — Falcor
deku-redux — Deku
Middleware
redux-thunk — The easiest way to write async action creators
redux-promise — FSA-compliant promise middleware
redux-rx — RxJS utilities for Redux, including a middleware for Observable
redux-logger — Log every Redux action and the next state
redux-immutable-state-invariant — Warns about state mutations in development
redux-analytics — Analytics middleware for Redux
redux-gen — Generator middleware for Redux
redux-saga — An alternative side effect model for Redux apps
Routing
redux-simple-router — Ruthlessly simple bindings to keep React Router and Redux in
sync
redux-router — Redux bindings for React Router
Components
redux-form — Keep React form state in Redux
Ecosystem 19
redux
Enhancers
redux-batched-subscribe — Customize batching and debouncing calls to the store
subscribers
redux-history-transitions — History transitions based on arbitrary actions
redux-optimist — Optimistically apply actions that can be later committed or reverted
redux-undo — Effortless undo/redo and action history for your reducers
redux-ignore — Ignore redux actions by array or filter function
redux-recycle — Reset the redux state on certain actions
redux-batched-actions — Dispatch several actions with a single subscriber notification
redux-search — Automatically index resources in a web worker and search them
without blocking
redux-electron-store — Store enhancers that synchronize Redux stores across Electron
processes
Utilities
reselect — Efficient derived data selectors inspired by NuclearJS
normalizr — Normalize nested API responses for easier consumption by the reducers
redux-actions — Reduces the boilerplate in writing reducers and action creators
redux-act — An opinionated library for making reducers and action creators
redux-transducers — Transducer utilities for Redux
redux-immutablejs — Integration tools between Redux and Immutable
redux-tcomb — Immutable and type-checked state and actions for Redux
redux-mock-store — Mock redux store for testing your app
Developer Tools
Redux DevTools — An action logger with time travel UI, hot reloading and error
handling for the reducers, first demoed at React Europe
Redux DevTools Extension — A Chrome extension wrapping Redux DevTools and
providing additional functionality
Community Conventions
Flux Standard Action — A human-friendly standard for Flux action objects
Canonical Reducer Composition — An opinionated standard for nested reducer
composition
Ducks: Redux Reducer Bundles — A proposal for bundling reducers, action types and
actions
Ecosystem 20
redux
Translations
中文文档 — Chinese
繁體中文文件 — Traditional Chinese
Redux in Russian — Russian
More
Awesome Redux is an extensive list of Redux-related repositories.
Ecosystem 21
redux
Examples
Redux is distributed with a few examples in its source code.
Note on Copying
If you copy Redux examples outside their folders, you can delete some lines at the end
of their webpack.config.js files. They follow a “You can safely delete these lines in your
project.” comment.
Counter
Run the Counter example:
cd redux/examples/counter
npm install
npm start
open http://localhost:3000/
It covers:
TodoMVC
Run the TodoMVC example:
cd redux/examples/todomvc
npm install
npm start
open http://localhost:3000/
It covers:
Examples 22
redux
cd redux/examples/todos-with-undo
npm install
npm start
open http://localhost:3000/
It covers:
Async
Run the Async example:
cd redux/examples/async
npm install
npm start
open http://localhost:3000/
It covers:
Universal
Run the Universal example:
Examples 23
redux
cd redux/examples/universal
npm install
npm start
open http://localhost:3000/
It covers:
Real World
Run the Real World example:
cd redux/examples/real-world
npm install
npm start
open http://localhost:3000/
It covers:
Shopping Cart
Run the Shopping Cart example:
cd redux/examples/shopping-cart
npm install
npm start
open http://localhost:3000/
Examples 24
redux
It covers:
Normalized state
Explicit entity ID tracking
Reducer composition
Queries defined alongside reducers
Example of rollback on failure
Safe conditional action dispatching
Using only React Redux to bind action creators
Conditional middleware (logging example)
More Examples
You can find more examples in Awesome Redux.
Examples 25
redux
Basics
Don’t be fooled by all the fancy talk about reducers, middleware, store enhancers—Redux is
incredibly simple. If you’ve ever built a Flux application, you will feel right at home. If you’re
new to Flux, it’s easy too!
In this guide, we’ll walk through the process of creating a simple Todo app.
Actions
Reducers
Store
Data Flow
Usage with React
Example: Todo List
Basics 26
redux
Actions
First, let’s define some actions.
Actions are payloads of information that send data from your application to your store. They
are the only source of information for the store. You send them to the store using
store.dispatch() .
{
type: ADD_TODO,
text: 'Build my first Redux app'
}
Actions are plain JavaScript objects. Actions must have a type property that indicates the
type of action being performed. Types should typically be defined as string constants. Once
your app is large enough, you may want to move them into a separate module.
Note on Boilerplate
You don’t have to define action type constants in a separate file, or even to define them
at all. For a small project, it might be easier to just use string literals for action types.
However, there are some benefits to explicitly declaring constants in larger codebases.
Read Reducing Boilerplate for more practical tips on keeping your codebase clean.
Other than type , the structure of an action object is really up to you. If you’re interested,
check out Flux Standard Action for recommendations on how actions could be constructed.
We’ll add one more action type to describe a user ticking off a todo as completed. We refer
to a particular todo by index because we store them in an array. In a real app, it is wiser to
generate a unique ID every time something new is created.
{
type: COMPLETE_TODO,
index: 5
}
Actions 27
redux
It’s a good idea to pass as little data in each action as possible. For example, it’s better to
pass index than the whole todo object.
Finally, we’ll add one more action type for changing the currently visible todos.
{
type: SET_VISIBILITY_FILTER,
filter: SHOW_COMPLETED
}
Action Creators
Action creators are exactly that—functions that create actions. It's easy to conflate the
terms “action” and “action creator,” so do your best to use the proper term.
In traditional Flux implementations, action creators often trigger a dispatch when invoked,
like so:
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
}
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
This makes them more portable and easier to test. To actually initiate a dispatch, pass the
result to the dispatch() function:
dispatch(addTodo(text))
dispatch(completeTodo(index))
Alternatively, you can create a bound action creator that automatically dispatches:
Actions 28
redux
boundAddTodo(text)
boundCompleteTodo(index)
The dispatch() function can be accessed directly from the store as store.dispatch() , but
more likely you'll access it using a helper like react-redux's connect() . You can use
bindActionCreators() to automatically bind many action creators to a dispatch() function.
Source Code
actions.js
/*
* action types
*/
/*
* other constants
*/
/*
* action creators
*/
Actions 29
redux
Next Steps
Now let’s define some reducers to specify how the state updates when you dispatch these
actions!
If you’re already familiar with the basic concepts and have previously completed this
tutorial, don’t forget to check out async actions in the advanced tutorial to learn how to
handle AJAX responses and compose action creators into async control flow.
Actions 30
redux
Reducers
Actions describe the fact that something happened, but don’t specify how the application’s
state changes in response. This is the job of a reducer.
You’ll often find that you need to store some data, as well as some UI state, in the state tree.
This is fine, but try to keep the data separate from the UI state.
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
Note on Relationships
In a more complex app, you’re going to want different entities to reference each other.
We suggest that you keep your state as normalized as possible, without any nesting.
Keep every entity in an object stored with an ID as a key, and use IDs to reference it
from other entities, or lists. Think of the app’s state as a database. This approach is
described in normalizr's documentation in detail. For example, keeping todosById: { id
-> todo } and todos: array<id> inside the state would be a better idea in a real app,
Reducers 31
redux
Handling Actions
Now that we’ve decided what our state object looks like, we’re ready to write a reducer for it.
The reducer is a pure function that takes the previous state and an action, and returns the
next state.
It’s called a reducer because it’s the type of function you would pass to
Array.prototype.reduce(reducer, ?initialValue) . It’s very important that the reducer stays
We’ll explore how to perform side effects in the advanced walkthrough. For now, just
remember that the reducer must be pure. Given the same arguments, it should calculate
the next state and return it. No surprises. No side effects. No API calls. No mutations.
Just a calculation.
With this out of the way, let’s start writing our reducer by gradually teaching it to understand
the actions we defined earlier.
We’ll start by specifying the initial state. Redux will call our reducer with an undefined state
for the first time. This is our chance to return the initial state of our app:
const initialState = {
visibilityFilter: VisibilityFilters.SHOW_ALL,
todos: []
}
One neat trick is to use the ES6 default arguments syntax to write this in a more compact
Reducers 32
redux
way:
Note that:
the first argument. You must supply an empty object as the first parameter. You can
also enable the experimental object spread syntax proposed for ES7 to write {
...state, ...newState } instead.
2. We return the previous state in the default case. It’s important to return the
previous state for any unknown action.
Note on Object.assign
Object.assign() is a part of ES6, but is not implemented by most browsers yet. You’ll
need to either use a polyfill, a Babel plugin, or a helper from another library like
_.assign() .
The switch statement is not the real boilerplate. The real boilerplate of Flux is
conceptual: the need to emit an update, the need to register the Store with a
Dispatcher, the need for the Store to be an object (and the complications that arise
when you want a universal app). Redux solves these problems by using pure reducers
instead of event emitters.
Reducers 33
redux
It’s unfortunate that many still choose a framework based on whether it uses switch
statements in the documentation. If you don’t like switch , you can use a custom
createReducer function that accepts a handler map, as shown in “reducing boilerplate”.
Just like before, we never write directly to state or its fields, and instead we return new
objects. The new todos is equal to the old todos concatenated with a single new item at
the end. The fresh todo was constructed using the data from the action.
case COMPLETE_TODO:
return Object.assign({}, state, {
todos: [
...state.todos.slice(0, action.index),
Object.assign({}, state.todos[action.index], {
completed: true
}),
...state.todos.slice(action.index + 1)
]
})
Because we want to update a specific item in the array without resorting to mutations, we
Reducers 34
redux
have to slice it before and after the item. If you find yourself often writing such operations, it’s
a good idea to use a helper like react-addons-update, updeep, or even a library like
Immutable that has native support for deep updates. Just remember to never assign to
anything inside the state unless you clone it first.
Splitting Reducers
Here is our code so far. It is rather verbose:
Is there a way to make it easier to comprehend? It seems like todos and visibilityFilter
are updated completely independently. Sometimes state fields depend on one another and
more consideration is required, but in our case we can easily split updating todos into a
separate function:
Reducers 35
redux
{
text: action.text,
completed: false
}
]
case COMPLETE_TODO:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
]
default:
return state
}
}
Note that todos also accepts state —but it’s an array! Now todoApp just gives it the slice of
the state to manage, and todos knows how to update just that slice. This is called reducer
composition, and it’s the fundamental pattern of building Redux apps.
Let’s explore reducer composition more. Can we also extract a reducer managing just
visibilityFilter ? We can:
Now we can rewrite the main reducer as a function that calls the reducers managing parts of
the state, and combines them into a single object. It also doesn’t need to know the complete
initial state anymore. It’s enough that the child reducers return their initial state when given
Reducers 36
redux
undefined at first.
Note that each of these reducers is managing its own part of the global state. The
state parameter is different for every reducer, and corresponds to the part of the
state it manages.
This is already looking good! When the app is larger, we can split the reducers into separate
files and keep them completely independent and managing different data domains.
Finally, Redux provides a utility called combineReducers() that does the same boilerplate
logic that the todoApp above currently does. With its help, we can rewrite todoApp like this:
Reducers 37
redux
You could also give them different keys, or call functions differently. These two ways to write
a combined reducer are completely equivalent:
All combineReducers() does is generate a function that calls your reducers with the slices of
state selected according to their keys, and combining their results into a single object
again. It’s not magic.
Because combineReducers expects an object, we can put all top-level reducers into a
separate file, export each reducer function, and use import * as reducers to get them
as an object with their names as the keys:
Reducers 38
redux
Because import * is still new syntax, we don’t use it anymore in the documentation to
avoid confusion, but you may encounter it in some community examples.
Source Code
reducers.js
Next Steps
Reducers 39
redux
Next, we’ll explore how to create a Redux store that holds the state and takes care of calling
your reducer when you dispatch an action.
Reducers 40
redux
Store
In the previous sections, we defined the actions that represent the facts about “what
happened” and the reducers that update the state according to those actions.
The Store is the object that brings them together. The store has the following
responsibilities:
It’s important to note that you’ll only have a single store in a Redux application. When you
want to split your data handling logic, you’ll use reducer composition instead of many stores.
It’s easy to create a store if you have a reducer. In the previous section, we used
combineReducers() to combine several reducers into one. We will now import it, and pass it
to createStore() .
You may optionally specify the initial state as the second argument to createStore() . This is
useful for hydrating the state of the client to match the state of a Redux application running
on the server.
Dispatching Actions
Now that we have created a store, let’s verify our program works! Even without any UI, we
can already test the update logic.
Store 41
redux
You can see how this causes the state held by the store to change:
We specified the behavior of our app before we even started writing the UI. We won’t do this
in this tutorial, but at this point you can write tests for your reducers and action creators. You
won’t need to mock anything because they are just functions. Call them, and make
assertions on what they return.
Source Code
index.js
Store 42
redux
Next Steps
Before creating a UI for our todo app, we will take a detour to see how the data flows in a
Redux application.
Store 43
redux
Data Flow
Redux architecture revolves around a strict unidirectional data flow.
This means that all data in an application follows the same lifecycle pattern, making the logic
of your app more predictable and easier to understand. It also encourages data
normalization, so that you don't end up with multiple, independent copies of the same data
that are unaware of one another.
If you're still not convinced, read Motivation and The Case for Flux for a compelling
argument in favor of unidirectional data flow. Although Redux is not exactly Flux, it shares
the same key benefits.
Think of an action as a very brief snippet of news. “Mary liked article 42.” or “‘Read the
Redux docs.’ was added to the list of todos.”
You can call store.dispatch(action) from anywhere in your app, including components
and XHR callbacks, or even at scheduled intervals.
2. The Redux store calls the reducer function you gave it.
The store will pass two arguments to the reducer: the current state tree and the action.
For example, in the todo app, the root reducer might receive something like this:
Data Flow 44
redux
Note that a reducer is a pure function. It only computes the next state. It should be
completely predictable: calling it with the same inputs many times should produce the
same outputs. It shouldn’t perform any side effects like API calls or router transitions.
These should happen before an action is dispatched.
3. The root reducer may combine the output of multiple reducers into a single state
tree.
How you structure the root reducer is completely up to you. Redux ships with a
combineReducers() helper function, useful for “splitting” the root reducer into separate
Here’s how combineReducers() works. Let’s say you have two reducers, one for a list of
todos, and another for the currently selected filter setting:
When you emit an action, todoApp returned by combineReducers will call both reducers:
It will then combine both sets of results into a single state tree:
return {
todos: nextTodos,
Data Flow 45
redux
visibleTodoFilter: nextVisibleTodoFilter
}
While combineReducers() is a handy helper utility, you don’t have to use it; feel free to
write your own root reducer!
4. The Redux store saves the complete state tree returned by the root reducer.
This new tree is now the next state of your app! Every listener registered with
store.subscribe(listener) will now be invoked; listeners may call store.getState() to
Now, the UI can be updated to reflect the new state. If you use bindings like React
Redux, this is the point at which component.setState(newState) is called.
Next Steps
Now that you know how Redux works, let’s connect it to a React app.
If you’re already familiar with the basic concepts and have previously completed this
tutorial, don’t forget to check out async flow in the advanced tutorial to learn how
middleware transforms async actions before they reach the reducer.
Data Flow 46
redux
That said, Redux works especially well with frameworks like React and Deku because they
let you describe UI as a function of state, and Redux emits state updates in response to
actions.
It is advisable that only top-level components of your app (such as route handlers) are aware
of Redux. Components below them should be presentational and receive all data via props.
In this todo app, we will only have a single container component at the top of our view
hierarchy. In more complex apps, you might have several of them. While you may nest
container components, we suggest that you pass props down whenever possible.
Remember how we designed the shape of the root state object? It’s time we design the UI
hierarchy to match it. This is not a Redux-specific task. Thinking in React is a great tutorial
that explains the process.
Our design brief is simple. We want to show a list of todo items. On click, a todo item is
crossed out as completed. We want to show a field where the user may add a new todo. In
the footer, we want to show a toggle to show all / only completed / only incomplete todos.
I see the following components (and their props) emerge from this brief:
'SHOW_ACTIVE' .
different filter.
These are all presentational components. They don’t know where the data comes from, or
how to change it. They only render what’s given to them.
If you migrate from Redux to something else, you’ll be able to keep all these components
exactly the same. They have no dependency on Redux.
Let’s write them! We don’t need to think about binding to Redux yet. You can just give them
fake data while you experiment until they render correctly.
Presentational Components
These are all normal React components, so we won’t stop to examine them in detail. Here
they go:
components/AddTodo.js
handleClick(e) {
const node = this.refs.input
const text = node.value.trim()
this.props.onAddClick(text)
node.value = ''
}
}
AddTodo.propTypes = {
onAddClick: PropTypes.func.isRequired
}
components/Todo.js
Todo.propTypes = {
onClick: PropTypes.func.isRequired,
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
}
components/TodoList.js
TodoList.propTypes = {
onTodoClick: PropTypes.func.isRequired,
todos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
}).isRequired).isRequired
}
components/Footer.js
return (
<a href='#' onClick={e => {
e.preventDefault()
this.props.onFilterChange(filter)
}}>
{name}
</a>
)
}
render() {
return (
<p>
Show:
{' '}
{this.renderFilter('SHOW_ALL', 'All')}
{', '}
{this.renderFilter('SHOW_COMPLETED', 'Completed')}
{', '}
{this.renderFilter('SHOW_ACTIVE', 'Active')}
.
</p>
)
}
Footer.propTypes = {
onFilterChange: PropTypes.func.isRequired,
filter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired
}
That’s it! We can verify that they work correctly by writing a dummy App to render them:
containers/App.js
Connecting to Redux
We need to make two changes to connect our App component to Redux and make it
dispatch actions and read state from the Redux store.
First, we need to import Provider from react-redux , which we installed earlier, and wrap
the root component in <Provider> before rendering.
index.js
This makes our store instance available to the components below. (Internally, this is done via
React’s “context” feature.)
Then, we wrap the components we want to connect to Redux with the connect()
function from react-redux . Try to only do this for a top-level component, or route handlers.
While technically you can connect() any component in your app to Redux store, avoid doing
this too deeply, because it will make the data flow harder to trace.
Any component wrapped with connect() call will receive a dispatch function as a
prop, and any state it needs from the global state. In most cases you will only pass the
first argument to connect() , which is a function we call a selector. This function takes the
global Redux store’s state, and returns the props you need for the component. In the
simplest case, you can just return the state given to you (i.e. pass identity function), but
you may also wish to transform it first.
containers/App.js
App.propTypes = {
visibleTodos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
}).isRequired).isRequired,
visibilityFilter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired
}
switch (filter) {
case VisibilityFilters.SHOW_ALL:
return todos
case VisibilityFilters.SHOW_COMPLETED:
return todos.filter(todo => todo.completed)
case VisibilityFilters.SHOW_ACTIVE:
return todos.filter(todo => !todo.completed)
}
}
Next Steps
Read the complete source code for this tutorial to better internalize the knowledge you have
gained. Then, head straight to the advanced tutorial to learn how to handle network requests
and routing!
Entry Point
index.js
/*
* action types
*/
/*
* other constants
*/
/*
* action creators
*/
let nextTodoId = 0;
Reducers
reducers.js
return {
...state,
completed: true
}
default:
return state
}
}
Container Components
containers/App.js
todos={visibleTodos}
onTodoClick={id =>
dispatch(completeTodo(id))
} />
<Footer
filter={visibilityFilter}
onFilterChange={nextFilter =>
dispatch(setVisibilityFilter(nextFilter))
} />
</div>
)
}
}
App.propTypes = {
visibleTodos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
}).isRequired).isRequired,
visibilityFilter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired
}
Presentational Components
components/AddTodo.js
handleClick(e) {
const node = this.refs.input
const text = node.value.trim()
this.props.onAddClick(text)
node.value = ''
}
}
AddTodo.propTypes = {
onAddClick: PropTypes.func.isRequired
}
components/Footer.js
return (
<a href='#' onClick={e => {
e.preventDefault()
this.props.onFilterChange(filter)
}}>
{name}
</a>
)
}
render() {
return (
<p>
Show:
{' '}
{this.renderFilter('SHOW_ALL', 'All')}
{', '}
{this.renderFilter('SHOW_COMPLETED', 'Completed')}
{', '}
{this.renderFilter('SHOW_ACTIVE', 'Active')}
.
</p>
)
}
}
Footer.propTypes = {
onFilterChange: PropTypes.func.isRequired,
filter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired
}
components/Todo.js
Todo.propTypes = {
onClick: PropTypes.func.isRequired,
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
}
components/TodoList.js
)}
</ul>
)
}
}
TodoList.propTypes = {
onTodoClick: PropTypes.func.isRequired,
todos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
}).isRequired).isRequired
}
Advanced
In the basics walkthrough, we explored how to structure a simple Redux application. In this
walkthrough, we will explore how AJAX and routing fit into the picture.
Async Actions
Async Flow
Middleware
Usage with React Router
Example: Reddit API
Next Steps
Advanced 62
redux
Async Actions
In the basics guide, we built a simple todo application. It was fully synchronous. Every time
an action was dispatched, the state was updated immediately.
In this guide, we will build a different, asynchronous application. It will use the Reddit API to
show the current headlines for a select subreddit. How does asynchronicity fit into Redux
flow?
Actions
When you call an asynchronous API, there are two crucial moments in time: the moment you
start the call, and the moment when you receive an answer (or a timeout).
Each of these two moments can usually require a change in the application state; to do that,
you need to dispatch normal actions that will be processed by reducers synchronously.
Usually, for any API request you’ll want to dispatch at least three different kinds of actions:
The reducers may handle this action by toggling an isFetching flag in the state. This
way the UI knows it’s time to show a spinner.
The reducers may handle this action by merging the new data into the state they
manage and resetting isFetching . The UI would hide the spinner, and display the
fetched data.
The reducers may handle this action by resetting isFetching . Maybe, some reducers
will also want to store the error message so the UI can display it.
{ type: 'FETCH_POSTS' }
{ type: 'FETCH_POSTS', status: 'error', error: 'Oops' }
{ type: 'FETCH_POSTS', status: 'success', response: { ... } }
Async Actions 63
redux
{ type: 'FETCH_POSTS_REQUEST' }
{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }
{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }
Choosing whether to use a single action type with flags, or multiple action types, is up to
you. It’s a convention you need to decide with your team. Multiple types leave less room for
a mistake, but this is not an issue if you generate action creators and reducers with a helper
library like redux-actions.
actions.js
These were the actions governed by the user interaction. We will also have another kind of
action, governed by the network requests. We will see how to dispatch them later, but for
now, we just want to define them.
When it’s time to fetch the posts for some reddit, we will dispatch a REQUEST_POSTS action:
Async Actions 64
redux
Finally, when the network request comes through, we will dispatch RECEIVE_POSTS :
This is all we need to know for now. The particular mechanism to dispatch these actions
together with network requests will be discussed later.
In a real app, you’d also want to dispatch an action on request failure. We won’t
implement error handling in this tutorial, but the real world example shows one of the
possible approaches.
This part is often confusing to beginners, because it is not immediately clear what
information describes the state of an asynchronous application, and how to organize it in a
single tree.
Async Actions 65
redux
We’ll start with the most common use case: lists. Web applications often show lists of things.
For example, a list of posts, or a list of friends. You’ll need to figure out what sorts of lists
your app can show. You want to store them separately in the state, because this way you
can cache them and only fetch again if necessary.
Here’s what the state shape for our “Reddit headlines” app might look like:
{
selectedReddit: 'frontend',
postsByReddit: {
frontend: {
isFetching: true,
didInvalidate: false,
items: []
},
reactjs: {
isFetching: false,
didInvalidate: false,
lastUpdated: 1439478405547,
items: [
{
id: 42,
title: 'Confusion about Flux and Relay'
},
{
id: 500,
title: 'Creating a Simple Application Using React JS and Flux Architecture'
}
]
}
}
}
For every list of items, you’ll want to store isFetching to show a spinner, didInvalidate
so you can later toggle it when the data is stale, lastUpdated so you know when it was
fetched the last time, and the items themselves. In a real app, you’ll also want to store
pagination state like fetchedPageCount and nextPageUrl .
In this example, we store the received items together with the pagination information.
Async Actions 66
redux
However, this approach won’t work well if you have nested entities referencing each
other, or if you let the user edit items. Imagine the user wants to edit a fetched post, but
this post is duplicated in several places in the state tree. This would be really painful to
implement.
If you have nested entities, or if you let users edit received entities, you should keep
them separately in the state as if it was a database. In pagination information, you
would only refer to them by their IDs. This lets you always keep them up to date. The
real world example shows this approach, together with normalizr to normalize the
nested API responses. With this approach, your state might look like this:
{
selectedReddit: 'frontend',
entities: {
users: {
2: {
id: 2,
name: 'Andrew'
}
},
posts: {
42: {
id: 42,
title: 'Confusion about Flux and Relay',
author: 2
},
100: {
id: 100,
title: 'Creating a Simple Application Using React JS and Flux Architecture',
author: 2
}
}
},
postsByReddit: {
frontend: {
isFetching: true,
didInvalidate: false,
items: []
},
reactjs: {
isFetching: false,
didInvalidate: false,
lastUpdated: 1439478405547,
items: [ 42, 100 ]
}
}
}
In this guide, we won’t normalize entities, but it’s something you should consider for a
more dynamic application.
Async Actions 67
redux
Handling Actions
Before going into the details of dispatching actions together with network requests, we will
write the reducers for the actions we defined above.
reducers.js
function posts(state = {
isFetching: false,
didInvalidate: false,
items: []
}, action) {
switch (action.type) {
case INVALIDATE_REDDIT:
return Object.assign({}, state, {
didInvalidate: true
})
case REQUEST_POSTS:
return Object.assign({}, state, {
isFetching: true,
didInvalidate: false
})
case RECEIVE_POSTS:
return Object.assign({}, state, {
isFetching: false,
didInvalidate: false,
items: action.posts,
lastUpdated: action.receivedAt
})
default:
return state
}
Async Actions 68
redux
is equivalent to this:
let nextState = {}
nextState[action.reddit] = posts(state[action.reddit], action)
return Object.assign({}, state, nextState)
We extracted posts(state, action) that manages the state of a specific post list. This is
just reducer composition! It is our choice how to split the reducer into smaller reducers,
and in this case, we’re delegating updating items inside an object to a posts reducer.
The real world example goes even further, showing how to create a reducer factory for
parameterized pagination reducers.
Remember that reducers are just functions, so you can use functional composition and
higher-order functions as much as you feel comfortable.
Async Actions 69
redux
Finally, how do we use the synchronous action creators we defined earlier together with
network requests? The standard way to do it with Redux is to use the Redux Thunk
middleware. It comes in a separate package called redux-thunk . We’ll explain how
middleware works in general later; for now, there is just one important thing you need to
know: by using this specific middleware, an action creator can return a function instead of an
action object. This way, the action creator becomes a thunk.
When an action creator returns a function, that function will get executed by the Redux
Thunk middleware. This function doesn’t need to be pure; it is thus allowed to have side
effects, including executing asynchronous API calls. The function can also dispatch actions
—like those synchronous actions we defined earlier.
We can still define these special thunk action creators inside our actions.js file:
actions.js
dispatch(requestPosts(reddit))
Async Actions 70
redux
return fetch(`http://www.reddit.com/r/${reddit}.json`)
.then(response => response.json())
.then(json =>
dispatch(receivePosts(reddit, json))
)
Note on fetch
We use fetch API in the examples. It is a new API for making network requests that
replaces XMLHttpRequest for most common needs. Because most browsers don’t yet
support it natively, we suggest that you use isomorphic-fetch library:
Internally, it uses whatwg-fetch polyfill on the client, and node-fetch on the server, so
you won’t need to change API calls if you change your app to be universal.
Be aware that any fetch polyfill assumes a Promise polyfill is already present. The
easiest way to ensure you have a Promise polyfill is to enable Babel’s ES6 polyfill in
your entry point before any other code runs:
How do we include the Redux Thunk middleware in the dispatch mechanism? We use the
applyMiddleware() method from Redux, as shown below:
index.js
Async Actions 71
redux
store.dispatch(selectReddit('reactjs'))
store.dispatch(fetchPosts('reactjs')).then(() =>
console.log(store.getState())
)
The nice thing about thunks is that they can dispatch results of each other:
actions.js
function fetchPosts(reddit) {
return dispatch => {
dispatch(requestPosts(reddit))
return fetch(`http://www.reddit.com/r/${reddit}.json`)
.then(response => response.json())
.then(json => dispatch(receivePosts(reddit, json)))
}
}
Async Actions 72
redux
} else if (posts.isFetching) {
return false
} else {
return posts.didInvalidate
}
}
This lets us write more sophisticated async control flow gradually, while the consuming code
can stay pretty much the same:
index.js
store.dispatch(fetchPostsIfNeeded('reactjs')).then(() =>
console.log(store.getState())
)
Async action creators are especially convenient for server rendering. You can create a
store, dispatch a single async action creator that dispatches other async action creators
to fetch data for a whole section of your app, and only render after the Promise it
returns completes. Then your store will already be hydrated with the state you need
before rendering.
Thunk middleware isn’t the only way to orchestrate asynchronous actions in Redux. You can
use redux-promise or redux-promise-middleware to dispatch Promises instead of functions.
You can dispatch Observables with redux-rx. You can even write a custom middleware to
describe calls to your API, like the real world example does. It is up to you to try a few
options, choose a convention you like, and follow it, whether with, or without the middleware.
Async Actions 73
redux
Connecting to UI
Dispatching async actions is no different from dispatching synchronous actions, so we won’t
discuss this in detail. See Usage with React for an introduction into using Redux from React
components. See Example: Reddit API for the complete source code discussed in this
example.
Next Steps
Read Async Flow to recap how async actions fit into the Redux flow.
Async Actions 74
redux
Async Flow
Without middleware, Redux store only supports synchronous data flow. This is what you get
by default with createStore() .
You may enhance createStore() with applyMiddleware() . It is not required, but it lets you
express asynchronous actions in a convenient way.
When the last middleware in the chain dispatches an action, it has to be a plain object. This
is when the synchronous Redux data flow takes place.
Check out the full source code for the async example.
Next Steps
Now you saw an example of what middleware can do in Redux, it’s time to learn how it
actually works, and how you can create your own. Go on to the next detailed section about
Middleware.
Async Flow 75
redux
Middleware
You’ve seen middleware in action in the Async Actions example. If you’ve used server-side
libraries like Express and Koa, you were also probably already familiar with the concept of
middleware. In these frameworks, middleware is some code you can put between the
framework receiving a request, and the framework generating a response. For example,
Express or Koa middleware may add CORS headers, logging, compression, and more. The
best feature of middleware is that it’s composable in a chain. You can use multiple
independent third-party middleware in a single project.
Redux middleware solves different problems than Express or Koa middleware, but in a
conceptually similar way. It provides a third-party extension point between dispatching
an action, and the moment it reaches the reducer. People use Redux middleware for
logging, crash reporting, talking to an asynchronous API, routing, and more.
This article is divided into an in-depth intro to help you grok the concept, and a few practical
examples to show the power of middleware at the very end. You may find it helpful to switch
back and forth between them, as you flip between feeling bored and inspired.
Understanding Middleware
While middleware can be used for a variety of things, including asynchronous API calls, it’s
really important that you understand where it comes from. We’ll guide you through the
thought process leading to middleware, by using logging and crash reporting as examples.
Problem: Logging
One of the benefits of Redux is that it makes state changes predictable and transparent.
Every time an action is dispatched, the new state is computed and saved. The state cannot
change by itself, it can only change as a consequence of a specific action.
Wouldn’t it be nice if we logged every action that happens in the app, together with the state
computed after it? When something goes wrong, we can look back at our log, and figure out
which action corrupted the state.
Middleware 76
redux
Note
If you’re using react-redux or similar bindings, you likely won’t have direct access to the
store instance in your components. For the next few paragraphs, just assume you pass
the store down explicitly.
store.dispatch(addTodo('Use Redux'))
To log the action and state, you can change it to something like this:
console.log('dispatching', action)
store.dispatch(action)
console.log('next state', store.getState())
This produces the desired effect, but you wouldn’t want to do it every time.
Middleware 77
redux
We could end this here, but it’s not very convenient to import a special function every time.
Wouldn’t it be useful if, any time an error is thrown as a result of dispatching an action, we
would send it to a crash reporting service like Sentry with the stack trace, the action that
caused the error, and the current state? This way it’s much easier to reproduce the error in
development.
However, it is important that we keep logging and crash reporting separate. Ideally we want
them to be different modules, potentially in different packages. Otherwise we can’t have an
ecosystem of such utilities. (Hint: we’re slowly getting to what middleware is!)
Middleware 78
redux
If logging and crash reporting are separate utilities, they might look like this:
function patchStoreToAddLogging(store) {
let next = store.dispatch
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
function patchStoreToAddCrashReporting(store) {
let next = store.dispatch
store.dispatch = function dispatchAndReportErrors(action) {
try {
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState()
}
})
throw err
}
}
}
If these functions are published as separate modules, we can later use them to patch our
store:
patchStoreToAddLogging(store)
patchStoreToAddCrashReporting(store)
function logger(store) {
let next = store.dispatch
// Previously:
// store.dispatch = function dispatchAndLog(action) {
Middleware 79
redux
We could provide a helper inside Redux that would apply the actual monkeypatching as an
implementation detail:
function logger(store) {
// Must point to the function returned by the previous middleware:
let next = store.dispatch
Middleware 80
redux
But there’s also a different way to enable chaining. The middleware could accept the next()
dispatch function as a parameter instead of reading it from the store instance.
function logger(store) {
return function wrapDispatchToAddLogging(next) {
return function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
}
It’s a “we need to go deeper” kind of moment, so it might take a while for this to make sense.
The function cascade feels intimidating. ES6 arrow functions make this currying easier on
eyes:
Now middleware takes the next() dispatch function, and returns a dispatch function, which
in turn serves as next() to the middleware to the left, and so on. It’s still useful to have
access to some store methods like getState() , so store stays available as the top-level
argument.
Middleware 81
redux
The implementation of applyMiddleware() that ships with Redux is similar, but different in
three important aspects:
It only exposes a subset of the store API to the middleware: dispatch(action) and
getState() .
It does a bit of trickery to make sure that if you call store.dispatch(action) from your
middleware instead of next(action) , the action will actually travel the whole middleware
chain again, including the current middleware. This is useful for asynchronous
middleware, as we have seen previously.
To ensure that you may only apply middleware once, it operates on createStore()
rather than on store itself. Instead of (store, middlewares) => store , its signature is
(...middlewares) => (createStore) => createStore .
Middleware 82
redux
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState()
}
})
throw err
}
}
That’s it! Now any actions dispatched to the store instance will flow through logger and
crashReporter :
Seven Examples
If your head boiled from reading the above section, imagine what it was like to write it. This
section is meant to be a relaxation for you and me, and will help get your gears turning.
Each function below is a valid Redux middleware. They are not equally useful, but at least
they are equally fun.
/**
* Logs all actions and states after they are dispatched.
*/
const logger = store => next => action => {
console.group(action.type)
console.info('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
console.groupEnd(action.type)
Middleware 83
redux
return result
}
/**
* Sends crash reports as state is updated and listeners are notified.
*/
const crashReporter = store => next => action => {
try {
return next(action)
} catch (err) {
console.error('Caught an exception!', err)
Raven.captureException(err, {
extra: {
action,
state: store.getState()
}
})
throw err
}
}
/**
* Schedules actions with { meta: { delay: N } } to be delayed by N milliseconds.
* Makes `dispatch` return a function to cancel the timeout in this case.
*/
const timeoutScheduler = store => next => action => {
if (!action.meta || !action.meta.delay) {
return next(action)
}
/**
* Schedules actions with { meta: { raf: true } } to be dispatched inside a rAF loop
* frame. Makes `dispatch` return a function to remove the action from the queue in
* this case.
*/
const rafScheduler = store => next => {
let queuedActions = []
let frame = null
function loop() {
frame = null
try {
if (queuedActions.length) {
next(queuedActions.shift())
}
} finally {
maybeRaf()
}
}
Middleware 84
redux
function maybeRaf() {
if (queuedActions.length && !frame) {
frame = requestAnimationFrame(loop)
}
}
queuedActions.push(action)
maybeRaf()
/**
* Lets you dispatch promises in addition to actions.
* If the promise is resolved, its result will be dispatched as an action.
* The promise is returned from `dispatch` so the caller may handle rejection.
*/
const vanillaPromise = store => next => action => {
if (typeof action.then !== 'function') {
return next(action)
}
return Promise.resolve(action).then(store.dispatch)
}
/**
* Lets you dispatch special actions with a { promise } field.
*
* This middleware will turn them into a single action at the beginning,
* and a single success (or failure) action when the `promise` resolves.
*
* For convenience, `dispatch` will return the promise so the caller can wait.
*/
const readyStatePromise = store => next => action => {
if (!action.promise) {
return next(action)
}
next(makeAction(false))
return action.promise.then(
result => next(makeAction(true, { result })),
error => next(makeAction(true, { error }))
)
}
Middleware 85
redux
/**
* Lets you dispatch a function instead of an action.
* This function will receive `dispatch` and `getState` as arguments.
*
* Useful for early exits (conditions over `getState()`), as well
* as for async control flow (it can `dispatch()` something else).
*
* `dispatch` will return the return value of the dispatched function.
*/
const thunk = store => next => action =>
typeof action === 'function' ?
action(store.dispatch, store.getState) :
next(action)
// You can use all of them! (It doesn’t mean you should.)
let createStoreWithMiddleware = applyMiddleware(
rafScheduler,
timeoutScheduler,
thunk,
vanillaPromise,
readyStatePromise,
logger,
crashReporter
)(createStore)
let todoApp = combineReducers(reducers)
let store = createStoreWithMiddleware(todoApp)
Middleware 86
redux
Entry Point
index.js
import 'babel-core/polyfill'
render(
<Root />,
document.getElementById('root')
)
function requestPosts(reddit) {
return {
type: REQUEST_POSTS,
reddit
}
}
function fetchPosts(reddit) {
return dispatch => {
dispatch(requestPosts(reddit))
return fetch(`http://www.reddit.com/r/${reddit}.json`)
.then(response => response.json())
.then(json => dispatch(receivePosts(reddit, json)))
}
}
Reducers
reducers.js
switch (action.type) {
case SELECT_REDDIT:
return action.reddit
default:
return state
}
}
function posts(state = {
isFetching: false,
didInvalidate: false,
items: []
}, action) {
switch (action.type) {
case INVALIDATE_REDDIT:
return Object.assign({}, state, {
didInvalidate: true
})
case REQUEST_POSTS:
return Object.assign({}, state, {
isFetching: true,
didInvalidate: false
})
case RECEIVE_POSTS:
return Object.assign({}, state, {
isFetching: false,
didInvalidate: false,
items: action.posts,
lastUpdated: action.receivedAt
})
default:
return state
}
}
Store
Example: Reddit API 89
redux
configureStore.js
Container Components
containers/Root.js
containers/AsyncApp.js
this.handleChange = this.handleChange.bind(this)
this.handleRefreshClick = this.handleRefreshClick.bind(this)
}
componentDidMount() {
const { dispatch, selectedReddit } = this.props
dispatch(fetchPostsIfNeeded(selectedReddit))
}
componentWillReceiveProps(nextProps) {
if (nextProps.selectedReddit !== this.props.selectedReddit) {
const { dispatch, selectedReddit } = nextProps
dispatch(fetchPostsIfNeeded(selectedReddit))
}
}
handleChange(nextReddit) {
this.props.dispatch(selectReddit(nextReddit))
}
handleRefreshClick(e) {
e.preventDefault()
render() {
const { selectedReddit, posts, isFetching, lastUpdated } = this.props
return (
<div>
<Picker value={selectedReddit}
onChange={this.handleChange}
options={[ 'reactjs', 'frontend' ]} />
<p>
{lastUpdated &&
<span>
Last updated at {new Date(lastUpdated).toLocaleTimeString()}.
{' '}
</span>
}
{!isFetching &&
<a href='#'
onClick={this.handleRefreshClick}>
Refresh
</a>
}
</p>
{isFetching && posts.length === 0 &&
<h2>Loading...</h2>
}
{!isFetching && posts.length === 0 &&
<h2>Empty.</h2>
}
{posts.length > 0 &&
<div style={{ opacity: isFetching ? 0.5 : 1 }}>
<Posts posts={posts} />
</div>
}
</div>
)
}
}
AsyncApp.propTypes = {
selectedReddit: PropTypes.string.isRequired,
posts: PropTypes.array.isRequired,
isFetching: PropTypes.bool.isRequired,
lastUpdated: PropTypes.number,
dispatch: PropTypes.func.isRequired
}
function mapStateToProps(state) {
const { selectedReddit, postsByReddit } = state
const {
isFetching,
lastUpdated,
items: posts
} = postsByReddit[selectedReddit] || {
isFetching: true,
items: []
}
return {
selectedReddit,
posts,
isFetching,
lastUpdated
}
}
Presentational Components
components/Picker.js
return (
<span>
<h1>{value}</h1>
<select onChange={e => onChange(e.target.value)}
value={value}>
{options.map(option =>
<option value={option} key={option}>
{option}
</option>)
}
</select>
</span>
)
}
}
Picker.propTypes = {
options: PropTypes.arrayOf(
PropTypes.string.isRequired
).isRequired,
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
}
components/Posts.js
Posts.propTypes = {
posts: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string.isRequired
}).isRequired).isRequired
}
Recipes
These are some use cases and code snippets to get you started with Redux in a real app.
They assume you understand the topics in basic and advanced tutorials.
Migrating to Redux
Reducing Boilerplate
Server Rendering
Writing Tests
Computing Derived Data
Implementing Undo History
Recipes 94
redux
Migrating to Redux
Redux is not a monolithic framework, but a set of contracts and a few functions that make
them work together. The majority of your “Redux code” will not even use Redux APIs, as
most of the time you’ll be writing functions.
From Flux
Reducers capture “the essence” of Flux Stores, so it’s possible to gradually migrate an
existing Flux project towards Redux, whether you are using Flummox, Alt, traditional Flux, or
any other Flux library.
It is also possible to do the reverse and migrate from Redux to any of these libraries
following the same steps.
the reducer for any action, store the next state, and emit change.
This allows you to gradually rewrite every Flux Store in your app as a reducer, but still
export createFluxStore(reducer) so the rest of your app is not aware that this is
happening and sees the Flux stores.
As you rewrite your Stores, you will find that you need to avoid certain Flux anti-patterns
such as fetching API inside the Store, or triggering actions inside the Stores. Your Flux
code will be easier to follow once you port it to be based on reducers!
When you have ported all of your Flux Stores to be implemented on top of reducers,
you can replace the Flux library with a single Redux store, and combine those reducers
you already have into one using combineReducers(reducers) .
Finally, you might want to begin using some Redux idioms like middleware to further
simplify your asynchronous code.
Migrating to Redux 95
redux
From Backbone
Backbone’s model layer is quite different from Redux, so we don’t suggest to mix them. If
possible, it is best that you rewrite your app’s model layer from scratch instead of connecting
Backbone to Redux. However, if a rewrite is not feasible, you may use backbone-redux to
migrate gradually, and keep the Redux store in sync with Backbone models and collections.
Migrating to Redux 96
redux
Reducing Boilerplate
Redux is in part inspired by Flux, and the most common complaint about Flux is how it
makes you write a lot of boilerplate. In this recipe, we will consider how Redux lets us
choose how verbose we’d like our code to be, depending on personal style, team
preferences, longer term maintainability, and so on.
Actions
Actions are plain objects describing what happened in the app, and serve as the sole way to
describe an intention to mutate the data. It’s important that actions being objects you have
to dispatch is not boilerplate, but one of the fundamental design choices of Redux.
There are frameworks claiming to be similar to Flux, but without a concept of action objects.
In terms of being predictable, this is a step backwards from Flux or Redux. If there are no
serializable plain object actions, it is impossible to record and replay user sessions, or to
implement hot reloading with time travel. If you’d rather modify data directly, you don’t need
Redux.
It is a common convention that actions have a constant type that helps reducers (or Stores
in Flux) identify them. We recommend that you use strings and not Symbols for action types,
because strings are serializable, and by using Symbols you make recording and replaying
harder than it needs to be.
In Flux, it is traditionally thought that you would define every action type as a string constant:
Why is this beneficial? It is often claimed that constants are unnecessary, and for small
projects, this might be correct. For larger projects, there are some benefits to defining
action types as constants:
Reducing Boilerplate 97
redux
It helps keep the naming consistent because all action types are gathered in a single
place.
Sometimes you want to see all existing actions before working on a new feature. It may
be that the action you need was already added by somebody on the team, but you
didn’t know.
The list of action types that were added, removed, and changed in a Pull Request helps
everyone on the team keep track of scope and implementation of new features.
If you make a typo when importing an action constant, you will get undefined . Redux
will immediately throw when dispatching such an action, and you’ll find the mistake
sooner.
It is up to you to choose the conventions for your project. You may start by using inline
strings, and later transition to constants, and maybe later group them into a single file.
Redux does not have any opinion here, so use your best judgment.
Action Creators
It is another common convention that, instead of creating action objects inline in the places
where you dispatch the actions, you would create functions generating them.
You might write an action creator in a separate file, and import it from your component:
actionCreators.js
AddTodo.js
Reducing Boilerplate 98
redux
Action creators have often been criticized as boilerplate. Well, you don’t have to write them!
You can use object literals if you feel this better suits your project. There are, however,
some benefits for writing action creators you should know about.
Let’s say a designer comes back to us after reviewing our prototype, and tells that we need
to allow three todos maximum. We can enforce this by rewriting our action creator to a
callback form with redux-thunk middleware and adding an early exit:
function addTodoWithoutCheck(text) {
return {
type: 'ADD_TODO',
text
}
}
dispatch(addTodoWithoutCheck(text))
}
}
We just modified how addTodo action creator behaves, completely invisible to the calling
code. We don’t have to worry about looking at each place where todos are being
added, to make sure they have this check. Action creators let you decouple additional
logic around dispatching an action, from the actual components emitting those actions. It’s
very handy when the application is under heavy development, and the requirements change
often.
Writing simple action creators can be tiresome and often ends up generating redundant
Reducing Boilerplate 99
redux
boilerplate code:
There are also utility libraries to aid in generating action creators, such as redux-act and
redux-actions. These can help with reducing your boilerplate code and adhering to
standards such as Flux Standard Action (FSA).
dispatched. Async actions are the most common use case for middleware.
Without any middleware, dispatch only accepts a plain object, so we have to perform AJAX
calls inside our components:
actionCreators.js
UserInfo.js
if (posts[userId]) {
// There is cached data! Don't do anything.
return
}
)
}
componentDidMount() {
this.loadData(this.props.userId)
}
componentWillReceiveProps(nextProps) {
if (nextProps.userId !== this.props.userId) {
this.loadData(nextProps.userId)
}
}
render() {
if (this.props.isFetching) {
return <p>Loading...</p>
}
return <div>{posts}</div>
}
}
However, this quickly gets repetitive because different components request data from the
same API endpoints. Moreover, we want to reuse some of this logic (e.g., early exit when
there is cached data available) from many components.
Middleware lets us write more expressive, potentially async action creators. It lets us
dispatch something other than plain objects, and interprets the values. For example,
middleware can “catch” dispatched Promises and turn them into a pair of request and
success/failure actions.
The simplest example of middleware is redux-thunk. “Thunk” middleware lets you write
action creators as “thunks”, that is, functions returning functions. This inverts the
control: you will get dispatch as an argument, so you can write an action creator that
dispatches many times.
Note
Thunk middleware is just one example of middleware. Middleware is not about “letting
you dispatch functions”: it’s about letting you dispatch anything that the particular
middleware you use knows how to handle. Thunk middleware adds a specific behavior
when you dispatch functions, but it really depends on the middleware you use.
actionCreators.js
dispatch({
type: 'LOAD_POSTS_REQUEST',
userId
})
UserInfo.js
componentWillReceiveProps(nextProps) {
if (nextProps.userId !== this.props.userId) {
this.props.dispatch(loadPosts(nextProps.userId))
}
}
render() {
if (this.props.isFetching) {
return <p>Loading...</p>
return <div>{posts}</div>
}
}
This is much less typing! If you’d like, you can still have “vanilla” action creators like
loadPostsSuccess which you’d use from a container loadPosts action creator.
Finally, you can write your own middleware. Let’s say you want to generalize the pattern
above and describe your async action creators like this instead:
The middleware that interprets such actions could look like this:
if (!types) {
// Normal action: pass it on
return next(action)
}
if (
!Array.isArray(types) ||
types.length !== 3 ||
!types.every(type => typeof type === 'string')
) {
throw new Error('Expected an array of three string types.')
}
if (!shouldCallAPI(getState())) {
return
}
dispatch(Object.assign({}, payload, {
type: requestType
}))
return callAPI().then(
response => dispatch(Object.assign({}, payload, {
response,
type: successType
})),
error => dispatch(Object.assign({}, payload, {
error,
type: failureType
}))
)
}
}
After passing it once to applyMiddleware(...middlewares) , you can write all your API-calling
action creators the same way:
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ message })
}),
payload: { postId, message }
}
}
Reducers
Redux reduces the boilerplate of Flux stores considerably by describing the update logic as
a function. A function is simpler than an object, and much simpler than a class.
let _todos = []
AppDispatcher.register(function (action) {
switch (action.type) {
case ActionTypes.ADD_TODO:
let text = action.text.trim()
_todos.push(text)
TodoStore.emitChange()
}
})
With Redux, the same update logic can be described as a reducing function:
The switch statement is not the real boilerplate. The real boilerplate of Flux is conceptual:
the need to emit an update, the need to register the Store with a Dispatcher, the need for the
Store to be an object (and the complications that arise when you want a universal app).
It’s unfortunate that many still choose Flux framework based on whether it uses switch
statements in the documentation. If you don’t like switch , you can solve this with a single
function, as we show below.
Generating Reducers
Let’s write a function that lets us express reducers as an object mapping from action types to
handlers. For example, if we want our todos reducers to be defined like this:
This wasn’t difficult, was it? Redux doesn’t provide such a helper function by default
because there are many ways to write it. Maybe you want it to automatically convert plain JS
objects to Immutable objects to hydrate the server state. Maybe you want to merge the
returned state with the current state. There may be different approaches to a “catch all”
handler. All of this depends on the conventions you choose for your team on a specific
project.
The Redux reducer API is (state, action) => state , but how you create those reducers is
up to you.
Server Rendering
The most common use case for server-side rendering is to handle the initial render when a
user (or search engine crawler) first requests our app. When the server receives the request,
it renders the required component(s) into an HTML string, and then sends it as a response
to the client. From that point on, the client takes over rendering duties.
We will use React in the examples below, but the same techniques can be used with other
view frameworks that can render on the server.
On the client side, a new Redux store will be created and initialized with the state provided
from the server.
Redux’s only job on the server side is to provide the initial state of our app.
Setting Up
In the following recipe, we are going to look at how to set up server-side rendering. We’ll use
the simplistic Counter app as a guide and show how the server can render state ahead of
time based on the request.
Install Packages
For this example, we’ll be using Express as a simple web server. We also need to install the
React bindings for Redux, since they are not included in Redux by default.
server.js
app.listen(port)
When rendering, we will wrap <App /> , our root component, inside a <Provider> to make
the store available to all components in the component tree, as we saw in Usage with React.
The key step in server side rendering is to render the initial HTML of our component before
we send it to the client side. To do this, we use ReactDOMServer.renderToString().
We then get the initial state from our Redux store using store.getState() . We will see how
this is passed along in our renderFullPage function.
We also include our bundle file for the client-side application via a script tag. This is
whatever output your bundling tool provides for your client entry point. It may be a static file
or a URL to a hot reloading development server.
In the example above, we use ES6 template strings syntax. It lets us write multiline
strings and interpolate values, but it requires ES6 support. If you’d like to write your
Node code using ES6, check out Babel require hook documentation. Or you can just
keep writing ES5 code.
client.js
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
You can set up your build tool of choice (Webpack, Browserify, etc.) to compile a bundle file
into dist/bundle.js .
When the page loads, the bundle file will be started up and ReactDOM.render() will hook into
the data-react-id attributes from the server-rendered HTML. This will connect our newly-
started React instance to the virtual DOM used on the server. Since we have the same initial
state for our Redux store and used the same code for all our view components, the result
will be the same real DOM.
And that’s it! That is all we need to do to implement server side rendering.
But the result is pretty vanilla. It essentially renders a static view from dynamic code. What
we need to do next is build an initial state dynamically to allow that rendered view to be
dynamic.
The request contains information about the URL requested, including any query parameters,
which will be useful when using something like React Router. It can also contain headers
with inputs like cookies or authorization, or POST body data. Let’s see how we can set the
initial counter state based on a query parameter.
server.js
res.send(renderFullPage(html, finalState))
}
The code reads from the Express Request object passed into our server middleware. The
parameter is parsed into a number and then set in the initial state. If you visit
http://localhost:3000/?counter=100 in your browser, you’ll see the counter starts at 100. In
the rendered HTML, you’ll see the counter output as 100 and the __INITIAL_STATE__ variable
has the counter set in it.
The easiest way to do this is to pass through some callback back to your synchronous code.
In this case, that will be a function that will reference the response object and send back our
rendered HTML to the client. Don’t worry, it’s not as hard as it may sound.
For our example, we’ll imagine there is an external datastore that contains the counter’s
initial value (Counter As A Service, or CaaS). We’ll make a mock call over to them and build
our initial state from the result. We’ll start by building out our API call:
api/counter.js
Again, this is just a mock API, so we use setTimeout to simulate a network request that
takes 500 milliseconds to respond (this should be much faster with a real world API). We
pass in a callback that returns a random number asynchronously. If you’re using a Promise-
based API client, then you would issue this callback in your then handler.
On the server side, we simply wrap our existing code in the fetchCounter and receive the
result in the callback:
server.js
Because we call res.send() inside of the callback, the server will hold open the connection
and won’t send any data until that callback executes. You’ll notice a 500ms delay is now
added to each server request as a result of our new API call. A more advanced usage would
handle errors in the API gracefully, such as a bad response or timeout.
Security Considerations
Because we have introduced more code that relies on user generated content (UGC) and
input, we have increased our attack surface area for our application. It is important for any
application that you ensure your input is properly sanitized to prevent things like cross-site
scripting (XSS) attacks or code injections.
In our example, we take a rudimentary approach to security. When we obtain the parameters
from the request, we use parseInt on the counter parameter to ensure this value is a
number. If we did not do this, you could easily get dangerous data into the rendered HTML
by providing a script tag in the request. That might look like this: ?counter=</script>
<script>doSomethingBad();</script>
For our simplistic example, coercing our input into a number is sufficiently secure. If you’re
handling more complex input, such as freeform text, then you should run that input through
an appropriate sanitization function, such as validator.js.
Furthermore, you can add additional layers of security by sanitizing your state output.
JSON.stringify can be subject to script injections. To counter this, you can scrub the JSON
string of HTML tags and other dangerous characters. This can be done with either a simple
text replacement on the string or via more sophisticated libraries such as serialize-javascript.
Next Steps
You may want to read Async Actions to learn more about expressing asynchronous flow in
Redux with async primitives such as Promises and thunks. Keep in mind that anything you
learn there can also be applied to universal rendering.
If you use something like React Router, you might also want to express your data fetching
dependencies as static fetchData() methods on your route handler components. They may
return async actions, so that your handleRender function can match the route to the route
handler component classes, dispatch fetchData() result for each of them, and render only
after the Promises have resolved. This way the specific API calls required for different routes
are colocated with the route handler component definitions. You can also use the same
technique on the client side to prevent the router from switching the page until its data has
been loaded.
Writing Tests
Because most of the Redux code you write are functions, and many of them are pure, they
are easy to test without mocking.
Setting Up
We recommend Mocha as the testing engine. Note that it runs in a Node environment, so
you won’t have access to the DOM.
{
...
"scripts": {
...
"test": "mocha --compilers js:babel-core/register --recursive",
"test:watch": "npm test -- --watch",
},
...
}
and run npm test to run it once, or npm run test:watch to test on every file change.
Action Creators
In Redux, action creators are functions which return plain objects. When testing action
creators we want to test whether the correct action creator was called and also whether the
right action was returned.
Example
describe('actions', () => {
it('should create an action to add a todo', () => {
const text = 'Finish docs'
const expectedAction = {
type: types.ADD_TODO,
text
}
expect(actions.addTodo(text)).toEqual(expectedAction)
})
})
Example
function fetchTodosRequest() {
return {
type: FETCH_TODOS_REQUEST
}
}
function fetchTodosSuccess(body) {
return {
type: FETCH_TODOS_SUCCESS,
body
}
}
function fetchTodosFailure(ex) {
return {
type: FETCH_TODOS_FAILURE,
ex
}
}
it('creates FETCH_TODOS_SUCCESS when fetching todos has been done', (done) => {
nock('http://example.com/')
.get('/todos')
.reply(200, { body: { todos: ['do something'] }})
const expectedActions = [
{ type: types.FETCH_TODOS_REQUEST },
{ type: types.FETCH_TODOS_SUCCESS, body: { todos: ['do something'] } }
]
const store = mockStore({ todos: [] }, expectedActions, done)
store.dispatch(actions.fetchTodos())
})
})
Reducers
A reducer should return the new state after applying the action to the previous state, and
that’s the behavior tested below.
Example
const initialState = [
{
text: 'Use Redux',
completed: false,
id: 0
}
]
completed: false,
text: action.text
},
...state
]
default:
return state
}
}
expect(
reducer(
[
{
text: 'Use Redux',
completed: false,
id: 0
}
],
{
type: types.ADD_TODO,
Components
A nice thing about React components is that they are usually small and only rely on their
props. That makes them easy to test.
To test the components we make a setup() helper that passes the stubbed callbacks as
props and renders the component with React shallow renderer. This lets individual tests
assert on whether the callbacks were called when expected.
Example
render() {
return (
<header className='header'>
<h1>todos</h1>
<TodoTextInput newTodo={true}
onSave={this.handleSave.bind(this)}
placeholder='What needs to be done?' />
</header>
)
}
}
Header.propTypes = {
addTodo: PropTypes.func.isRequired
}
function setup() {
let props = {
addTodo: expect.createSpy()
}
return {
props,
output,
renderer
}
}
describe('components', () => {
describe('Header', () => {
it('should render correctly', () => {
const { output } = setup()
expect(output.type).toBe('header')
expect(output.props.className).toBe('header')
expect(h1.type).toBe('h1')
expect(h1.props.children).toBe('todos')
expect(input.type).toBe(TodoTextInput)
expect(input.props.newTodo).toBe(true)
expect(input.props.placeholder).toBe('What needs to be done?')
})
It’s important that this code is evaluated before React is imported. To ensure this, modify
your mocha command to include --require ./test/setup.js in the options in your
package.json :
{
...
"scripts": {
...
"test": "mocha --compilers js:babel/register --recursive --require ./test/setup.js",
},
...
}
Connected Components
If you use a library like React Redux, you might be using higher-order components like
connect() . This lets you inject Redux state into a regular React component.
In a unit test, you would normally import the App component like this:
However, when you import it, you’re actually holding the wrapper component returned by
connect() , and not the App component itself. If you want to test its interaction with Redux,
this is good news: you can wrap it in a <Provider> with a store created specifically for this
unit test. But sometimes you want to test just the rendering of the component, without a
Redux store.
In order to be able to test the App component itself without having to deal with the decorator,
we recommend you to also export the undecorated component:
Since the default export is still the decorated component, the import statement pictured
above will work as before so you won’t have to change your application code. However, you
can now import the undecorated App components in your test file like this:
// Note the curly braces: grab the named export instead of default export
import { App } from './App'
If you are using ES6 in your application source, but write your tests in ES5, you should
know that Babel handles the interchangeable use of ES6 import and CommonJS
require through its interop capability to run two module formats side-by-side, but the
behavior is slightly different. If you add a second export beside your default export, you
can no longer import the default using require('./App') . Instead you have to use
require('./App').default .
Middleware
Middleware functions wrap behavior of dispatch calls in Redux, so to test this modified
behavior we need to mock the behavior of the dispatch call.
Example
describe('middleware', () => {
it('should dispatch if store is empty', () => {
const action = {
type: types.ADD_TODO
}
expect(
dispatchWithStoreOf({}, action)
).toEqual(action)
})
expect(
dispatchWithStoreOf({
[types.ADD_TODO]: 'dispatched'
}, action)
).toNotExist()
})
})
Glossary
React Test Utils: Test Utilities for React.
jsdom: A plain JavaScript implementation of the DOM API. jsdom allows us to run the
tests without browser.
Shallow rendering: Shallow rendering lets you instantiate a component and get the
result of its render method just a single level deep instead of rendering components
recursively to a DOM. The result of shallow rendering is a ReactElement. That means it
is possible to access its children, props and test if it works as expected. This also
means that you changing a child component won’t affect the tests for parent
component.
containers/App.js
App.propTypes = {
visibleTodos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
})),
visibilityFilter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired
}
function select(state) {
return {
visibleTodos: selectTodos(state.todos, state.visibilityFilter),
visibilityFilter: state.visibilityFilter
}
}
In the above example, select calls selectTodos to calculate visibleTodos . This works
great, but there is a drawback: visibleTodos is calculated every time the component is
updated. If the state tree is large, or the calculation expensive, repeating the calculation on
every update may cause performance problems. Reselect can help to avoid these
unnecessary recalculations.
If the Redux state tree is mutated in a way that causes the value of an input-selector to
change, the selector will call its transform function with the values of the input-selectors as
arguments and return the result. If the values of the input-selectors are the same as the
previous call to the selector, it will return the previously computed value instead of calling the
transform function.
selectors/todoSelectors.js
Composing Selectors
A memoized selector can itself be an input-selector to another memoized selector. Here is
visibleTodosSelector being used as an input-selector to a selector that further filters the
todos by keyword:
If you are using react-redux, you connect a memoized selector to the Redux store using
connect :
containers/App.js
App.propTypes = {
visibleTodos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
})),
visibilityFilter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired
}
This means that implementing Undo and Redo in an MVC application usually forces you to
rewrite parts of your application to use a specific data mutation pattern like Command.
With Redux, however, implementing undo history is a breeze. There are three reasons for
this:
There are no multiple models—just a state subtree that you want to keep track of.
The state is already immutable, and mutations are already described as discrete
actions, which is close to the undo stack mental model.
The reducer (state, action) => state signature makes it natural to implement generic
“reducer enhancers” or “higher order reducers”. They are functions that take your
reducer and enhance it with some additional functionality while preserving its signature.
Undo history is exactly such a case.
Before proceeding, make sure you have worked through the basics tutorial and understand
reducer composition well. This recipe will build on top of the example described in the basics
tutorial.
In the first part of this recipe, we will explain the underlying concepts that make Undo and
Redo possible to implement in a generic way.
In the second part of this recipe, we will show how to use Redux Undo package that
provides this functionality out of the box.
For example, the state shape of a counter app might look like this:
{
counter: 10
}
If we wanted to implement Undo and Redo in such an app, we’d need to store more state so
we can answer the following questions:
It is reasonable to suggest that our state shape should change to answer these questions:
{
counter: {
past: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
present: 10,
future: []
}
}
Now, if user presses “Undo”, we want it to change to move into the past:
{
counter: {
past: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ],
present: 9,
future: [ 10 ]
}
}
{
counter: {
past: [ 0, 1, 2, 3, 4, 5, 6, 7 ],
present: 8,
future: [ 9, 10 ]
}
}
When the user presses “Redo”, we want to move one step back into the future:
{
counter: {
past: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ],
present: 9,
future: [ 10 ]
}
}
Finally, if the user performs an action (e.g. decrement the counter) while we’re in the middle
of the undo stack, we’re going to discard the existing future:
{
counter: {
past: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
present: 8,
future: []
}
}
The interesting part here is that it does not matter whether we want to keep an undo stack of
numbers, strings, arrays, or objects. The structure will always be the same:
{
counter: {
past: [ 0, 1, 2 ],
present: 3,
future: [ 4 ]
}
}
{
todos: {
past: [
[],
[ { text: 'Use Redux' } ],
[ { text: 'Use Redux', complete: true } ]
],
present: [ { text: 'Use Redux', complete: true }, { text: 'Implement Undo' } ],
future: [
[ { text: 'Use Redux', complete: true }, { text: 'Implement Undo', complete: true }
]
}
}
{
past: Array<T>,
present: T,
future: Array<T>
}
{
past: [
{ counterA: 1, counterB: 1 },
{ counterA: 1, counterB: 0 },
{ counterA: 0, counterB: 0 }
],
present: { counterA: 2, counterB: 1 },
future: []
}
Or many granular histories so user can undo and redo actions in them independently:
{
counterA: {
past: [ 1, 0 ],
present: 2,
future: []
},
counterB: {
past: [ 0 ],
present: 1,
future: []
}
}
We will see later how the approach we take lets us choose how granular Undo and Redo
need to be.
{
past: Array<T>,
present: T,
future: Array<T>
}
Let’s talk through the algorithm to manipulate the state shape described above. We can
define two actions to operate on this state: UNDO and REDO . In our reducer, we will do the
following steps to handle these actions:
Handling Undo
Remove the last element from the past .
Set the present to the element we removed in the previous step.
Insert the old present state at the beginning of the future .
Handling Redo
Remove the first element from the future .
Set the present to the element we removed in the previous step.
Insert the old present state at the end of the past .
const initialState = {
past: [],
present: null, // (?) How do we initialize the present?
future: []
}
switch (action.type) {
case 'UNDO':
const previous = past[past.length - 1]
const newPast = past.slice(0, past.length - 1)
return {
past: newPast,
present: previous,
future: [ present, ...future ]
}
case 'REDO':
const next = future[0]
const newFuture = future.slice(1)
return {
past: [ ...past, present ],
present: next,
future: newFuture
}
default:
// (?) How do we handle other actions?
return state
}
}
`
This implementation isn’t usable because it leaves out three important questions:
Where do we get the initial present state from? We don’t seem to know it beforehand.
Where do we react to the external actions to save the present to the past ?
How do we actually delegate the control over the present state to a custom reducer?
It seems that reducer isn’t the right abstraction, but we’re very close.
A reducer enhancer (or a higher order reducer) is a function that takes a reducer, and
returns a new reducer that is able to handle new actions, or to hold more state, delegating
control to the inner reducer for the actions it doesn’t understand. This isn’t a new pattern—
technically, combineReducers() is also a reducer enhancer because it takes reducers and
returns a new reducer.
function doNothingWith(reducer) {
return function (state, action) {
// Just call the passed reducer
return reducer(state, action)
}
}
A reducer enhancer that combines other reducers might look like this:
function combineReducers(reducers) {
return function (state = {}, action) {
return Object.keys(reducers).reduce((nextState, key) => {
// Call every reducer with the part of the state it manages
nextState[key] = reducers[key](state[key], action)
return nextState
}, {})
}
}
function undoable(reducer) {
// Call the reducer with empty action to populate the initial state
const initialState = {
past: [],
present: reducer(undefined, {}),
future: []
}
switch (action.type) {
case 'UNDO':
const previous = past[past.length - 1]
const newPast = past.slice(0, past.length - 1)
return {
past: newPast,
present: previous,
future: [ present, ...future ]
}
case 'REDO':
const next = future[0]
const newFuture = future.slice(1)
return {
past: [ ...past, present ],
present: next,
future: newFuture
}
default:
// Delegate handling the action to the passed reducer
const newPresent = reducer(present, action)
if (present === newPresent) {
return state
}
return {
past: [ ...past, present ],
present: newPresent,
future: []
}
}
}
}
We can now wrap any reducer into undoable reducer enhancer to teach it to react to UNDO
and REDO actions.
// This is a reducer
function todos(state = [], action) {
/* ... */
}
store.dispatch({
type: 'ADD_TODO',
text: 'Use Redux'
})
store.dispatch({
type: 'ADD_TODO',
text: 'Implement Undo'
})
store.dispatch({
type: 'UNDO'
})
There is an important gotcha: you need to remember to append .present to the current
state when you retrieve it. You may also check .past.length and .future.length to
determine whether to enable or to disable the Undo and Redo buttons, respectively.
You might have heard that Redux was influenced by Elm Architecture. It shouldn’t come as a
surprise that this example is very similar to elm-undo-redo package.
In this part of the recipe, you will learn how to make the Todo List example undoable. You
can find the full source of this recipe in the todos-with-undo example that comes with
Redux.
Installation
First of all, you need to run
This installs the package that provides the undoable reducer enhancer.
reducers.js
/* ... */
The distinctState() filter serves to ignore the actions that didn’t result in a state change.
There are many other options to configure your undoable reducer, like setting the action type
for Undo and Redo actions.
You may wrap one or more reducers in undoable at any level of the reducer composition
hierarchy. We choose to wrap todos instead of the top-level combined reducer so that
changes to visibilityFilter are not reflected in the undo history.
{
visibilityFilter: 'SHOW_ALL',
todos: {
past: [
[],
[ { text: 'Use Redux' } ],
[ { text: 'Use Redux', complete: true } ]
],
present: [ { text: 'Use Redux', complete: true }, { text: 'Implement Undo' } ],
future: [
[ { text: 'Use Redux', complete: true }, { text: 'Implement Undo', complete: true }
]
}
}
This means you need to access your state with state.todos.present instead of just
state.todos :
containers/App.js
function select(state) {
const presentTodos = state.todos.present
return {
visibleTodos: selectTodos(presentTodos, state.visibilityFilter),
visibilityFilter: state.visibilityFilter
}
}
In order to disable the Undo and Redo buttons when there is nothing to undo or redo, you
need to check whether the past and future arrays are empty:
containers/App.js
function select(state) {
return {
undoDisabled: state.todos.past.length === 0,
redoDisabled: state.todos.future.length === 0,
visibleTodos: selectTodos(state.todos.present, state.visibilityFilter),
visibilityFilter: state.visibilityFilter
};
}
First of all, you need to import ActionCreators from redux-undo and pass their bound
versions to the Footer component:
containers/App.js
/* ... */
components/Footer.js
/* ... */
renderUndo() {
return (
<p>
<button onClick={this.props.onUndo} disabled={this.props.undoDisabled}>Undo</button
<button onClick={this.props.onRedo} disabled={this.props.redoDisabled}>Redo</button
</p>
)
}
render() {
return (
<div>
{this.renderFilters()}
{this.renderUndo()}
</div>
)
}
}
This is it! Run npm install and npm start in the example folder and try it out!
Troubleshooting
This is a place to share common problems and solutions to them.
The examples use React, but you should still find them useful if you use something else.
Redux assumes that you never mutate the objects it gives to you in the reducer. Every
single time, you must return the new state object. Even if you don’t use a library like
Immutable, you need to completely avoid mutation.
For example, a reducer like this is wrong because it mutates the state:
Troubleshooting 141
redux
switch (action.type) {
case 'ADD_TODO':
// Return a new array
return [
...state,
{
text: action.text,
completed: false
}
]
case 'COMPLETE_TODO':
// Return a new array
return [
...state.slice(0, action.index),
// Copy the object before mutating
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
]
default:
return state
}
}
It’s more code, but it’s exactly what makes Redux predictable and efficient. If you want to
have less code, you can use a helper like React.addons.update to write immutable
transformations with a terse syntax:
// Before:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
]
// After
return update(state, {
[action.index]: {
completed: {
$set: true
}
}
})
Finally, to update objects, you’ll need something like _.extend from Underscore, or better,
an Object.assign polyfill.
Make sure that you use Object.assign correctly. For example, instead of returning
something like Object.assign(state, newData) from your reducers, return Object.assign({},
state, newData) . This way you don’t override the previous state .
Troubleshooting 142
redux
You can also enable ES7 object spread proposal with Babel stage 1:
// Before:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
]
// After:
return [
...state.slice(0, action.index),
{ ...state[action.index], completed: true },
...state.slice(action.index + 1)
]
Note that experimental language features are subject to change, and it’s unwise to rely on
them in large codebases.
TodoActions.js
AddTodo.js
render() {
return (
<button onClick={() => this.handleClick()}>
Add
</button>
)
}
Troubleshooting 143
redux
It doesn’t work because your action creator is just a function that returns an action. It is up to
you to actually dispatch it. We can’t bind your action creators to a particular Store instance
during the definition because apps that render on the server need a separate Redux store
for every request.
handleClick() {
// Works! (but you need to grab store somehow)
store.dispatch(addTodo('Fix the issue'))
}
If you’re somewhere deep in the component hierarchy, it is cumbersome to pass the store
down manually. This is why react-redux lets you use a connect higher-order component that
will, apart from subscribing you to a Redux store, inject dispatch into your component’s
props.
AddTodo.js
render() {
return (
<button onClick={() => this.handleClick()}>
Add
</button>
)
}
}
You can then pass dispatch down to other components manually, if you want to.
Troubleshooting 144
redux
Troubleshooting 145
redux
Glossary
This is a glossary of the core terms in Redux, along with their type signatures. The types are
documented using Flow notation.
State
State (also called the state tree) is a broad term, but in the Redux API it usually refers to the
single state value that is managed by the store and returned by getState() . It represents
the entire state of a Redux application, which is often a deeply nested object.
By convention, the top-level state is an object or some other key-value collection like a Map,
but technically it can be any type. Still, you should do your best to keep the state
serializable. Don’t put anything inside it that you can’t easily turn into JSON.
Action
An action is a plain object that represents an intention to change the state. Actions are the
only way to get data into the store. Any data, whether from UI events, network callbacks, or
other sources such as WebSockets needs to eventually be dispatched as actions.
Actions must have a type field that indicates the type of action being performed. Types can
be defined as constants and imported from another module. It’s better to use strings for
type than Symbols because strings are serializable.
Other than type , the structure of an action object is really up to you. If you’re interested,
check out Flux Standard Action for recommendations on how actions should be constructed.
Reducer
Glossary 146
redux
A reducer (also called a reducing function) is a function that accepts an accumulation and a
value and returns a new accumulation. They are used to reduce a collection of values down
to a single value.
In Redux, the accumulated value is the state object, and the values being accumulated are
actions. Reducers calculate a new state given the previous state and an action. They must
be pure functions—functions that return the exact same output for given inputs. They should
also be free of side-effects. This is what enables exciting features like hot reloading and time
travel.
Dispatching Function
A dispatching function (or simply dispatch function) is a function that accepts an action or an
async action; it then may or may not dispatch one or more actions to the store.
We must distinguish between dispatching functions in general and the base dispatch
function provided by the store instance without any middleware.
The base dispatch function always synchronously sends an action to the store’s reducer,
along with the previous state returned by the store, to calculate a new state. It expects
actions to be plain objects ready to be consumed by the reducer.
Middleware wraps the base dispatch function. It allows the dispatch function to handle async
actions in addition to actions. Middleware may transform, delay, ignore, or otherwise
interpret actions or async actions before passing them to the next middleware. See below for
more information.
Action Creator
Glossary 147
redux
An action creator is, quite simply, a function that creates an action. Do not confuse the two
terms—again, an action is a payload of information, and an action creator is a factory that
creates an action.
Calling an action creator only produces an action, but does not dispatch it. You need to call
the store’s dispatch function to actually cause the mutation. Sometimes we say bound
action creators to mean functions that call an action creator and immediately dispatch its
result to a specific store instance.
If an action creator needs to read the current state, perform an API call, or cause a side
effect, like a routing transition, it should return an async action instead of an action.
Async Action
An async action is a value that is sent to a dispatching function, but is not yet ready for
consumption by the reducer. It will be transformed by middleware into an action (or a series
of actions) before being sent to the base dispatch() function. Async actions may have
different types, depending on the middleware you use. They are often asynchronous
primitives, like a Promise or a thunk, which are not passed to the reducer immediately, but
trigger action dispatches once an operation has completed.
Middleware
Glossary 148
redux
Store
type Store = {
dispatch: Dispatch
getState: () => State
subscribe: (listener: () => void) => () => void
replaceReducer: (reducer: Reducer) => void
}
Store creator
A store creator is a function that creates a Redux store. Like with dispatching function, we
must distinguish the base store creator, createStore(reducer, initialState) exported from
the Redux package, from store creators that are returned from the store enhancers.
Store enhancer
A store enhancer is a higher-order function that composes a store creator to return a new,
enhanced store creator. This is similar to middleware in that it allows you to alter the store
interface in a composable way.
Store enhancers are much the same concept as higher-order components in React, which
are also occasionally called “component enhancers”.
Glossary 149
redux
Because a store is not an instance, but rather a plain-object collection of functions, copies
can be easily created and modified without mutating the original store. There is an example
in compose documentation demonstrating that.
Most likely you’ll never write a store enhancer, but you may use the one provided by the
developer tools. It is what makes time travel possible without the app being aware it is
happening. Amusingly, the Redux middleware implementation is itself a store enhancer.
Glossary 150
redux
API Reference
The Redux API surface is tiny. Redux defines a set of contracts for you to implement (such
as reducers) and provides a few helper functions to tie these contracts together.
This section documents the complete Redux API. Keep in mind that Redux is only
concerned with managing the state. In a real app, you’ll also want to use UI bindings like
react-redux.
Top-Level Exports
createStore(reducer, [initialState])
combineReducers(reducers)
applyMiddleware(...middlewares)
bindActionCreators(actionCreators, dispatch)
compose(...functions)
Store API
Store
getState()
dispatch(action)
subscribe(listener)
replaceReducer(nextReducer)
Importing
Every function described above is a top-level export. You can import any of them like this:
ES6
ES5 (CommonJS)
createStore(reducer, [initialState])
Creates a Redux store that holds the complete state tree of your app.
There should only be a single store in your app.
Arguments
1. reducer (Function): A reducing function that returns the next state tree, given the
2. [ initialState ] (any): The initial state. You may optionally specify it to hydrate the state
from the server in universal apps, or to restore a previously serialized user session. If
you produced reducer with combineReducers , this must be a plain object with the same
shape as the keys passed to it. Otherwise, you are free to pass anything that your
reducer can understand.
Returns
( Store ): An object that holds the complete state of your app. The only way to change its
state is by dispatching actions. You may also subscribe to the changes to its state to update
the UI.
Example
store.dispatch({
type: 'ADD_TODO',
text: 'Read the docs'
})
console.log(store.getState())
// [ 'Use Redux', 'Read the docs' ]
createStore 153
redux
Tips
Don’t create more than one store in an application! Instead, use combineReducers to
create a single root reducer out of many.
It is up to you to choose the state format. You can use plain objects or something like
Immutable. If you’re not sure, start with plain objects.
If your state is a plain object, make sure you never mutate it! For example, instead of
returning something like Object.assign(state, newData) from your reducers, return
Object.assign({}, state, newData) . This way you don’t override the previous state .
You can also write return { ...state, ...newData } if you enable ES7 object spread
proposal with Babel stage 1.
For universal apps that run on the server, create a store instance with every request so
that they are isolated. Dispatch a few data fetching actions to a store instance and wait
for them to complete before rendering the app on the server.
When a store is created, Redux dispatches a dummy action to your reducer to populate
the store with the initial state. You are not meant to handle the dummy action directly.
Just remember that your reducer should return some kind of initial state if the state
given to it as the first argument is undefined , and you’re all set.
createStore 154
redux
Store
A store holds the whole state tree of your application.
The only way to change the state inside it is to dispatch an action on it.
A store is not a class. It’s just an object with a few methods on it.
To create it, pass your root reducing function to createStore .
If you’re coming from Flux, there is a single important difference you need to
understand. Redux doesn’t have a Dispatcher or support many stores. Instead, there
is just a single store with a single root reducing function. As your app grows,
instead of adding stores, you split the root reducer into smaller reducers independently
operating on the different parts of the state tree. You can use a helper like
combineReducers to combine them. This is similar to how there is just one root
Store Methods
getState()
dispatch(action)
subscribe(listener)
replaceReducer(nextReducer)
Store Methods
getState()
Returns the current state tree of your application.
It is equal to the last value returned by the store’s reducer.
Returns
(any): The current state tree of your application.
dispatch(action)
Store 155
redux
The store’s reducing function will be called with the current getState() result and the given
action synchronously. Its return value will be considered the next state. It will be returned
from getState() from now on, and the change listeners will immediately be notified.
If you attempt to call dispatch from inside the reducer, it will throw with an error saying
“Reducers may not dispatch actions.” This is similar to “Cannot dispatch in a middle of
dispatch” error in Flux, but doesn’t cause the problems associated with it. In Flux, a
dispatch is forbidden while Stores are handling the action and emitting updates. This is
unfortunate because it makes it impossible to dispatch actions from component lifecycle
hooks or other benign places.
In Redux, subscriptions are called after the root reducer has returned the new state, so
you may dispatch in the subscription listeners. You are only disallowed to dispatch
inside the reducers because they must have no side effects. If you want to cause a side
effect in response to an action, the right place to do this is in the potentially async action
creator.
Arguments
1. action (Object†): A plain object describing the change that makes sense for your
application. Actions are the only way to get data into the store, so any data, whether
from the UI events, network callbacks, or other sources such as WebSockets needs to
eventually be dispatched as actions. Actions must have a type field that indicates the
type of action being performed. Types can be defined as constants and imported from
another module. It’s better to use strings for type than Symbols because strings are
serializable. Other than type , the structure of an action object is really up to you. If
you’re interested, check out Flux Standard Action for recommendations on how actions
could be constructed.
Returns
(Object†): The dispatched action (see notes).
Notes
†
The “vanilla” store implementation you get by calling createStore only supports plain
object actions and hands them immediately to the reducer.
However, if you wrap createStore with applyMiddleware , the middleware can interpret
Store 156
redux
actions differently, and provide support for dispatching async actions. Async actions are
usually asynchronous primitives like Promises, Observables, or thunks.
Middleware is created by the community and does not ship with Redux by default. You need
to explicitly install packages like redux-thunk or redux-promise to use it. You may also create
your own middleware.
To learn how to describe asynchronous API calls, read the current state inside action
creators, perform side effects, or chain them to execute in a sequence, see the examples for
applyMiddleware .
Example
function addTodo(text) {
return {
type: 'ADD_TODO',
text
}
}
subscribe(listener)
Adds a change listener. It will be called any time an action is dispatched, and some part of
the state tree may potentially have changed. You may then call getState() to read the
current state tree inside the callback.
It is a low-level API. Most likely, instead of using it directly, you’ll use React (or other)
bindings. If you feel that the callback needs to be invoked with the current state, you might
want to convert the store to an Observable or write a custom observeStore utility instead.
Arguments
1. listener (Function): The callback to be invoked any time an action has been
dispatched, and the state tree might have changed. You may call getState() inside this
callback to read the current state tree. It is reasonable to expect that the store’s reducer
is a pure function, so you may compare references to some deep path in the state tree
Store 157
redux
Returns
Example
function select(state) {
return state.some.deep.property
}
let currentValue
function handleChange() {
let previousValue = currentValue
currentValue = select(store.getState())
replaceReducer(nextReducer)
Replaces the reducer currently used by the store to calculate the state.
It is an advanced API. You might need this if your app implements code splitting, and you
want to load some of the reducers dynamically. You might also need this if you implement a
hot reloading mechanism for Redux.
Arguments
1. reducer (Function) The next reducer for the store to use.
Store 158
redux
combineReducers(reducers)
As your app grows more complex, you’ll want to split your reducing function into separate
functions, each managing independent parts of the state.
The combineReducers helper function turns an object whose values are different reducing
functions into a single reducing function you can pass to createStore .
The resulting reducer calls every child reducer, and gather their results into a single state
object. The shape of the state object matches the keys of the passed reducers .
{
reducer1: ...
reducer2: ...
}
You can control state key names by using different keys for the reducers in the passed
object. For example, you may call combineReducers({ todos: myTodosReducer, counter:
myCounterReducer }) for the state shape to be { todos, counter } .
A popular convention is to name reducers after the state slices they manage, so you can use
ES6 property shorthand notation: combineReducers({ counter, todos }) . This is equivalent to
writing combineReducers({ counter: counter, todos: todos }) .
This function helps you organize your reducers to manage their own slices of state,
similar to how you would have different Flux Stores to manage different state. With
Redux, there is just one store, but combineReducers helps you keep the same logical
division between reducers.
Arguments
1. reducers (Object): An object whose values correspond to different reducing functions
that need to be combined into one. See the notes below for some rules every passed
reducer must follow.
Earlier documentation suggested the use of the ES6 import * as reducers syntax to
obtain the reducers object. This was the source of a lot of confusion, which is why we
now recommend exporting a single reducer obtained using combineReducers() from
combineReducers 159
redux
Returns
(Function): A reducer that invokes every reducer inside the reducers object, and constructs
a state object with the same shape.
Notes
This function is mildly opinionated and is skewed towards helping beginners avoid common
pitfalls. This is why it attempts to enforce some rules that you don’t have to follow if you write
the root reducer manually.
For any action that is not recognized, it must return the state given to it as the first
argument.
It must never return undefined . It is too easy to do this by mistake via an early return
statement, so combineReducers throws if you do that instead of letting the error manifest
itself somewhere else.
If the state given to it is undefined , it must return the initial state for this specific
reducer. According to the previous rule, the initial state must not be undefined either. It
is handy to specify it with ES6 optional arguments syntax, but you can also explicitly
check the first argument for being undefined .
While combineReducers attempts to check that your reducers conform to some of these rules,
you should remember them, and do your best to follow them.
Example
reducers/todos.js
reducers/counter.js
combineReducers 160
redux
reducers/index.js
App.js
store.dispatch({
type: 'ADD_TODO',
text: 'Use Redux'
})
console.log(store.getState())
// {
// counter: 0,
// todos: [ 'Use Redux' ]
// }
Tips
This helper is just a convenience! You can write your own combineReducers that works
differently, or even assemble the state object from the child reducers manually and write
a root reducing function explicitly, like you would write any other function.
combineReducers 161
redux
You may call combineReducers at any level of the reducer hierarchy. It doesn’t have to
happen at the top. In fact you may use it again to split the child reducers that get too
complicated into independent grandchildren, and so on.
combineReducers 162
redux
applyMiddleware(...middlewares)
Middleware is the suggested way to extend Redux with custom functionality. Middleware lets
you wrap the store’s dispatch method for fun and profit. The key feature of middleware is
that it is composable. Multiple middleware can be combined together, where each
middleware requires no knowledge of what comes before or after it in the chain.
The most common use case for middleware is to support asynchronous actions without
much boilerplate code or a dependency on a library like Rx. It does so by letting you
dispatch async actions in addition to normal actions.
For example, redux-thunk lets the action creators invert control by dispatching functions.
They would receive dispatch as an argument and may call it asynchronously. Such
functions are called thunks. Another example of middleware is redux-promise. It lets you
dispatch a Promise async action, and dispatches a normal action when the Promise
resolves.
Middleware is not baked into createStore and is not a fundamental part of the Redux
architecture, but we consider it useful enough to be supported right in the core. This way,
there is a single standard way to extend dispatch in the ecosystem, and different
middleware may compete in expressiveness and utility.
Arguments
...middlewares (arguments): Functions that conform to the Redux middleware API.
Returns
(Function) A store enhancer that applies the given middleware. The store enhancer is a
function that needs to be applied to createStore . It will return a different createStore which
has the middleware enabled.
store.dispatch({
type: 'ADD_TODO',
text: 'Understand the middleware'
})
// (These lines will be logged by the middleware:)
// will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' }
// state after dispatch: [ 'Use Redux', 'Understand the middleware' ]
function fetchSecretSauce() {
return fetch('https://www.google.com/search?q=secret+sauce')
}
// These are the normal action creators you have seen so far.
// The actions they return can be dispatched without any middleware.
// However, they only express “facts” and not the “async flow”.
applyMiddleware 164
redux
}
}
function withdrawMoney(amount) {
return {
type: 'WITHDRAW',
amount
}
}
// Meet thunks.
// A thunk is a function that returns a function.
// This is a thunk.
function makeASandwichWithSecretSauce(forPerson) {
// Invert control!
// Return a function that accepts `dispatch` so we can dispatch later.
// Thunk middleware knows how to turn thunk async actions into actions.
store.dispatch(
makeASandwichWithSecretSauce('Me')
)
store.dispatch(
makeASandwichWithSecretSauce('My wife')
).then(() => {
console.log('Done!')
})
applyMiddleware 165
redux
function makeSandwichesForEverybody() {
return function (dispatch, getState) {
if (!getState().sandwiches.isShopOpen) {
return Promise.resolve()
}
return dispatch(
makeASandwichWithSecretSauce('My Grandma')
).then(() =>
Promise.all([
dispatch(makeASandwichWithSecretSauce('Me')),
dispatch(makeASandwichWithSecretSauce('My wife'))
])
).then(() =>
dispatch(makeASandwichWithSecretSauce('Our kids'))
).then(() =>
dispatch(getState().myMoney > 42 ?
withdrawMoney(42) :
apologize('Me', 'The Sandwich Shop')
)
)
}
}
// This is very useful for server side rendering, because I can wait
// until data is available, then synchronously render the app.
store.dispatch(
makeSandwichesForEverybody()
).then(() =>
response.send(renderToString(<MyApp store={store} />))
)
applyMiddleware 166
redux
componentWillReceiveProps(nextProps) {
if (nextProps.forPerson !== this.props.forPerson) {
this.props.dispatch(
makeASandwichWithSecretSauce(nextProps.forPerson)
)
}
}
render() {
return <p>{this.props.sandwiches.join('mustard')}</p>
}
}
Tips
Middleware only wraps the store’s dispatch function. Technically, anything a
middleware can do, you can do manually by wrapping every dispatch call, but it’s
easier to manage this in a single place and define action transformations on the scale of
the whole project.
If you use other store enhancers in addition to applyMiddleware , make sure to put
applyMiddleware before them in the composition chain because the middleware is
If you want to conditionally apply a middleware, make sure to only import it when it’s
needed:
let middleware = [ a, b ]
if (process.env.NODE_ENV !== 'production') {
let c = require('some-debug-middleware');
let d = require('another-debug-middleware');
middleware = [ ...middleware, c, d ];
}
const createStoreWithMiddleware = applyMiddleware(...middleware)(createStore);
This makes it easier for bundling tools to cut out unneeded modules and reduces the
size of your builds.
applyMiddleware 167
redux
most powerful Redux extension mechanism called store enhancers. It is highly unlikely
you’ll ever want to write a store enhancer yourself. Another example of a store enhancer
is redux-devtools. Middleware is less powerful than a store enhancer, but it is easier to
write.
Middleware sounds much more complicated than it really is. The only way to really
understand middleware is to see how the existing middleware works, and try to write
your own. The function nesting can be intimidating, but most of the middleware you’ll
find are, in fact, 10-liners, and the nesting and composability is what makes the
middleware system powerful.
applyMiddleware 168
redux
bindActionCreators(actionCreators,
dispatch)
Turns an object whose values are action creators, into an object with the same keys, but
with every action creator wrapped into a dispatch call so they may be invoked directly.
Normally you should just call dispatch directly on your Store instance. If you use Redux
with React, react-redux will provide you with the dispatch function so you can call it directly,
too.
The only use case for bindActionCreators is when you want to pass some action creators
down to a component that isn’t aware of Redux, and you don’t want to pass dispatch or the
Redux store to it.
For convenience, you can also pass a single function as the first argument, and get a
function in return.
Parameters
1. actionCreators (Function or Object): An action creator, or an object whose values are
action creators.
Returns
(Function or Object): An object mimicking the original object, but with each function
immediately dispatching the action returned by the corresponding action creator. If you
passed a function as actionCreators , the return value will also be a single function.
Example
TodoActionCreators.js
bindActionCreators 169
redux
return {
type: 'REMOVE_TODO',
id
}
}
SomeComponent.js
render() {
// Injected by react-redux:
let { todos, dispatch } = this.props
return (
<TodoList todos={todos}
{...boundActionCreators} />
)
bindActionCreators 170
redux
Tips
You might ask: why don’t we bind the action creators to the store instance right away,
like in classical Flux? The problem is that this won’t work well with universal apps that
need to render on the server. Most likely you want to have a separate store instance per
request so you can prepare them with different data, but binding action creators during
their definition means you’re stuck with a single store instance for all requests.
If you use ES5, instead of import * as syntax you can just pass
require('./TodoActionCreators') to bindActionCreators as the first argument. The only
thing it cares about is that the values of the actionCreators arguments are functions.
The module system doesn’t matter.
bindActionCreators 171
redux
compose(...functions)
Composes functions from right to left.
Arguments
1. (arguments): The functions to compose. Each function is expected to accept a single
parameter. Its return value will be provided as an argument to the function standing to
the left, and so on.
Returns
(Function): The final function obtained by composing the given functions from right to left.
Example
This example demonstrates how to use compose to enhance a store with applyMiddleware
and a few developer tools from the redux-devtools package.
let finalCreateStore
compose 172
redux
//
// finalCreateStore = applyMiddleware(middleware)(
// require('redux-devtools').devTools()(
// require('redux-devtools').persistState(
// window.location.href.match(/[?&]debug_session=([^&]+)\b/)
// )(createStore)
// )
// )
}
Tips
All compose does is let you write deeply nested function transformations without the
rightward drift of the code. Don’t give it too much credit!
compose 173
redux
Change Log
This project adheres to Semantic Versioning.
Every release, along with the migration instructions, is documented on the Github Releases
page.
Patrons
The work on Redux was funded by the community.
Meet some of the outstanding companies and individuals that made it possible:
Webflow
Chess iX
Herman J. Radtke III
Ken Wheeler
Chung Yen Li
Sunil Pai
Charlie Cheever
Eugene G
Matt Apperson
Jed Watson
Sasha Aickin
Stefan Tennigkeit
Sam Vincent
Olegzandr Denman
Patrons 175