Redux
  • Read Me
  • Introduction
    • Motivation
    • Core Concepts
    • Three Principles
    • Prior Art
    • Learning Resources
    • Ecosystem
    • Examples
  • Basics
    • Actions
    • Reducers
    • Store
    • Data Flow
    • Usage with React
    • Example: Todo List
  • Advanced
    • Async Actions
    • Async Flow
    • Middleware
    • Usage with React Router
    • Example: Reddit API
    • Next Steps
  • Recipes
    • Configuring Your Store
    • Migrating to Redux
    • Using Object Spread Operator
    • Reducing Boilerplate
    • Server Rendering
    • Writing Tests
    • Computing Derived Data
    • Implementing Undo History
    • Isolating Subapps
    • Structuring Reducers
      • Prerequisite Concepts
      • Basic Reducer Structure
      • Splitting Reducer Logic
      • Refactoring Reducers Example
      • Using combineReducers
      • Beyond combineReducers
      • Normalizing State Shape
      • Updating Normalized Data
      • Reusing Reducer Logic
      • Immutable Update Patterns
      • Initializing State
    • Using Immutable.JS with Redux
  • FAQ
    • General
    • Reducers
    • Organizing State
    • Store Setup
    • Actions
    • Immutable Data
    • Code Structure
    • Performance
    • Design Decisions
    • React Redux
    • Miscellaneous
  • Troubleshooting
  • Glossary
  • API Reference
    • createStore
    • Store
    • combineReducers
    • applyMiddleware
    • bindActionCreators
    • compose
  • Change Log
  • Patrons
  • Feedback
Powered by GitBook
On this page
  • Table of Contents
  • Design Decisions
  • Why doesn't Redux pass the state and action to subscribers?
  • Why doesn't Redux support using classes for actions and reducers?
  • Why does the middleware signature use currying?
  • Why does applyMiddleware use a closure for dispatch?
  • Why doesn't combineReducers include a third argument with the entire state when it calls each reducer?
  • Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?
  1. FAQ

Design Decisions

PreviousPerformanceNextReact Redux

Last updated 7 years ago

Table of Contents

Design Decisions

Why doesn't Redux pass the state and action to subscribers?

Subscribers are intended to respond to the state value itself, not the action. Updates to the state are processed synchronously, but notifications to subscribers can be batched or debounced, meaning that subscribers are not always notified with every action. This is a common to avoid repeated re-rendering.

Batching or debouncing is possible by using enhancers to override store.dispatch to change the way that subscribers are notified. Also, there are libraries that change Redux to process actions in batches to optimize performance and avoid repeated re-rendering:

  • allows passing an array of actions to store.dispatch() with only one notification,

  • allows batching of subscribe notifications that occur as a result of dispatches.

The intended guarantee is that Redux eventually calls all subscribers with the most recent state available, but not that it always calls each subscriber for each action. The store state is available in the subscriber simply by calling store.getState(). The action cannot be made available in the subscribers without breaking the way that actions might be batched.

A potential use-case for using the action inside a subscriber -- which is an unsupported feature -- is to ensure that a component only re-renders after certain kinds of actions. Instead, re-rendering should be controlled through:

Further Information

Articles

Discussions

Why doesn't Redux support using classes for actions and reducers?

The pattern of using functions, called action creators, to return action objects may seem counterintuitive to programmers with a lot of Object Oriented Programming experience, who would see this is a strong use-case for Classes and instances. Class instances for action objects and reducers are not supported because class instances make serialization and deserialization tricky. Deserialization methods like JSON.parse(string) will return a plain old Javascript object rather than class instances.

Serialization enables the browser to store all actions that have been dispatched, as well as the previous store states, with much less memory. Rewinding and 'hot reloading' the store is central to the Redux developer experience and the function of Redux DevTools. This also enables deserialized actions to be stored on the server and re-serialized in the browser in the case of server-side rendering with Redux.

Further Information

Articles

Discussions

Why does the middleware signature use currying?

Redux middleware are written using a triply-nested function structure that looks like const middleware = storeAPI => next => action => {}, rather than a single function that looks like const middleware = (storeAPI, next, action) => {}. There's a few reasons for this.

One is that "currying" functions is a standard functional programming technique, and Redux was explicitly intended to use functional programming principles in its design. Another is that currying functions creates closures where you can declare variables that exist for the lifetime of the middleware (which could be considered a functional equivalent to instance variables that exist for the lifetime of a class instance). Finally, it's simply the approach that was chosen when Redux was initially designed.

Further Information

Discussions

  • Why does the middleware signature use currying?

Why does applyMiddleware use a closure for dispatch?

Further Information

Discussions

  • Why does applyMiddleware use a closure for dispatch?

Why doesn't combineReducers include a third argument with the entire state when it calls each reducer?

If none of the published utilities solve your use case, you can always write a function yourself that does just exactly what you need.

Further information

Articles

Discussions

Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?

There have been requests to use either the entire state or the return value of mapState inside of mapDispatch, so that when functions are declared inside of mapDispatch, they can close over the latest returned values from the store.

This approach is not supported in mapDispatch because it would mean also calling mapDispatch every time the store is updated. This would cause the re-creation of functions with every state update, thus adding a lot of performance overhead.

The preferred way to handle this use-case--needing to alter props based on the current state and mapDispatchToProps functions--is to work from mergeProps, the third argument to the connect function. If specified, it is passed the result of mapStateToProps(), mapDispatchToProps(), and the container component's props. The plain object returned from mergeProps will be passed as props to the wrapped component.

Further information

Discussions

the lifecycle method

the

Using React-Redux: use to subscribe components to only the parts of the store that they need.

As described in the , if you are okay with things like persistence and time-travel debugging not working as intended, you are welcome to put non-serializable items into your Redux store.

The of declaring middleware is by some, because both store and next are available when the applyMiddleware function is executed. This issue has been determined to not be , as there are now hundreds of middleware in the Redux ecosystem that rely on the existing middleware definition.

Prior discussions: , , , ,

applyMiddleware takes the existing dispatch from the store and closes over it to create the initial chain of middlewares that have been invoked with an object that exposes the getState and dispatch functions, which enables middlewares that to run.

See - and

combineReducers is opinionated to encourage splitting reducer logic by domain. As stated in ,combineReducers is deliberately limited to handle a single common use case: updating a state tree that is a plain Javascript object by delegating the work of updating each slice of state to a specific slice reducer.

It's not immediately obvious what a potential third argument to each reducer should be: the entire state tree, some callback function, some other part of the state tree, etc. If combineReducers doesn't fit your use case, consider using libraries like or for other options with deeply nested reducers and reducers that require access to the global state.

shouldComponentUpdate
virtual DOM equality check (vDOMEq)
React.PureComponent
mapStateToProps
#580: Why doesn't Redux pass the state to subscribers?
#2214: Alternate Proof of Concept: Enhancer Overhaul -- more on debouncing
#1171: Why doesn't Redux use classes for actions and reducers?
curried function signature
deemed unnecessary
worth introducing breaking changes
#55
#534
#784
#922
#1744
React Boston 2017: You Might Need Redux (And Its Ecosystem)
rely on dispatch during initialization
#1592
#2097
Beyond combineReducers
combineSectionReducers
reduceReducers
Beyond combineReducers
#1768 Allow reducers to consult global state
#237 Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?
performance optimization
redux-batch
redux-batched-subscribe
Why doesn't Redux pass the state and action to subscribers?
Why doesn't Redux support using classes for actions and reducers?
Why does the middleware signature use currying?
Why does applyMiddleware use a closure for dispatch?
Why doesn't combineReducers include a third argument with the entire state when it calls each reducer?
Why doesn't mapDispatchToProps allow use of return values from getState() or mapStateToProps()?
How can I reduce the number of store update events?
Store FAQ
Can I put functions, promises, or other non-serializable items in my store state?