mapStateToProps
Connect: Extracting Data with As the first argument passed in to connect
, mapStateToProps
is used for selecting the part of the data from the store that the connected component needs. It’s frequently referred to as just mapState
for short.
- It is called every time the store state changes.
- It receives the entire store state, and should return an object of data this component needs.
mapStateToProps
Defining mapStateToProps
should be defined as a function:
It should take a first argument called state
, optionally a second argument called ownProps
, and return a plain object containing the data that the connected component needs.
This function should be passed as the first argument to connect
, and will be called every time when the Redux store state changes. If you do not wish to subscribe to the store, pass null
or undefined
to connect
in place of mapStateToProps
.
It does not matter if a mapStateToProps
function is written using the function
keyword (function mapState(state) { }
) or as an arrow function (const mapState = (state) => { }
) - it will work the same either way.
Arguments
state
ownProps
(optional)
state
The first argument to a mapStateToProps
function is the entire Redux store state (the same value returned by a call to store.getState()
). Because of this, the first argument is traditionally just called state
. (While you can give the argument any name you want, calling it store
would be incorrect - it's the "state value", not the "store instance".)
The mapStateToProps
function should always be written with at least state
passed in.
ownProps
(optional)
You may define the function with a second argument, ownProps
, if your component needs the data from its own props to retrieve data from the store. This argument will contain all of the props given to the wrapper component that was generated by connect
.
You do not need to include values from ownProps
in the object returned from mapStateToProps
. connect
will automatically merge those different prop sources into a final set of props.
Return
Your mapStateToProps
function should return a plain object that contains the data the component needs:
- Each field in the object will become a prop for your actual component
- The values in the fields will be used to determine if your component needs to re-render
For example:
Note: In advanced scenarios where you need more control over the rendering performance,
mapStateToProps
can also return a function. In this case, that function will be used as the finalmapStateToProps
for a particular component instance. This allows you to do per-instance memoization. See the Advanced Usage section of the docs for more details, as well as PR #279 and the tests it adds. Most apps never need this.
Usage Guidelines
mapStateToProps
Reshape the Data from the Store
Let mapStateToProps
functions can, and should, do a lot more than just return state.someSlice
. They have the responsibility of "re-shaping" store data as needed for that component. This may include returning a value as a specific prop name, combining pieces of data from different parts of the state tree, and transforming the store data in different ways.
Use Selector Functions to Extract and Transform Data
We highly encourage the use of "selector" functions to help encapsulate the process of extracting values from specific locations in the state tree. Memoized selector functions also play a key role in improving application performance (see the following sections in this page and the Advanced Usage: Performance page for more details on why and how to use selectors.)
mapStateToProps
Functions Should Be Fast
Whenever the store changes, all of the mapStateToProps
functions of all of the connected components will run. Because of this, your mapStateToProps
functions should run as fast as possible. This also means that a slow mapStateToProps
function can be a potential bottleneck for your application.
As part of the "re-shaping data" idea, mapStateToProps
functions frequently need to transform data in various ways (such as filtering an array, mapping an array of IDs to their corresponding objects, or extracting plain JS values from Immutable.js objects). These transformations can often be expensive, both in terms of cost to execute the transformation, and whether the component re-renders as a result. If performance is a concern, ensure that these transformations are only run if the input values have changed.
mapStateToProps
Functions Should Be Pure and Synchronous
Much like a Redux reducer, a mapStateToProps
function should always be 100% pure and synchronous. It should simply take state
(and ownProps
) as arguments, and return the data the component needs as props. It should not be used to trigger asynchronous behavior like AJAX calls for data fetching, and the functions should not be declared as async
.
mapStateToProps
and Performance
Return Values Determine If Your Component Re-Renders
React-Redux internally implements the shouldComponentUpdate
method such that the wrapper component re-renders precisely when the data your component needs has changed. By default, React-Redux decides whether the contents of the object returned from mapStateToProps
are different using ===
comparison (a "shallow equality" check) on each fields of the returned object. If any of the fields have changed, then your component will be re-rendered so it can receive the updated values as props. Note that returning a mutated object of the same reference is a common mistake that can result in your component not re-rendering when expected.
To summarize the behavior of the component wrapped by connect
with mapStateToProps
to extract data from the store:
(state) => stateProps | (state, ownProps) => stateProps | |
---|---|---|
mapStateToProps runs when: | store state changes | store state changes or any field of ownProps is different |
component re-renders when: | any field of stateProps is different | any field of stateProps is different or any field of ownProps is different |
Only Return New Object References If Needed
React-Redux does shallow comparisons to see if the mapStateToProps
results have changed. It’s easy to accidentally return new object or array references every time, which would cause your component to re-render even if the data is actually the same.
Many common operations result in new object or array references being created:
- Creating new arrays with
someArray.map()
orsomeArray.filter()
- Merging arrays with
array.concat
- Selecting portion of an array with
array.slice
- Copying values with
Object.assign
- Copying values with the spread operator
{ ...oldState, ...newData }
Put these operations in memoized selector functions to ensure that they only run if the input values have changed. This will also ensure that if the input values haven't changed, mapStateToProps
will still return the same result values as before, and connect
can skip re-rendering.
Only Perform Expensive Operations When Data Changes
Transforming data can often be expensive (and usually results in new object references being created). In order for your mapStateToProps
function to be as fast as possible, you should only re-run these complex transformations when the relevant data has changed.
There are a few ways to approach this:
- Some transformations could be calculated in an action creator or reducer, and the transformed data could be kept in the store
- Transformations can also be done in a component's
render()
method - If the transformation does need to be done in a
mapStateToProps
function, then we recommend using memoized selector functions to ensure the transformation is only run when the input values have changed.
Immutable.js Performance Concerns
Immutable.js author Lee Byron on Twitter explicitly advises avoiding toJS
when performance is a concern:
Perf tip for #immutablejs: avoid .toJS() .toObject() and .toArray() all slow full-copy operations which render structural sharing useless.
There's several other performance concerns to take into consideration with Immutable.js - see the list of links at the end of this page for more information.
Behavior and Gotchas
mapStateToProps
Will Not Run if the Store State is the Same
The wrapper component generated by connect
subscribes to the Redux store. Every time an action is dispatched, it calls store.getState()
and checks to see if lastState === currentState
. If the two state values are identical by reference, then it will not re-run your mapStateToProps
function, because it assumes that the rest of the store state hasn't changed either.
The Redux combineReducers
utility function tries to optimize for this. If none of the slice reducers returned a new value, then combineReducers
returns the old state object instead of a new one. This means that mutation in a reducer can lead to the root state object not being updated, and thus the UI won't re-render.
The Number of Declared Arguments Affects Behavior
With just (state)
, the function runs whenever the root store state object is different. With (state, ownProps)
, it runs any time the store state is different and ALSO whenever the wrapper props have changed.
This means that you should not add the ownProps
argument unless you actually need to use it, or your mapStateToProps
function will run more often than it needs to.
There are some edge cases around this behavior. The number of mandatory arguments determines whether mapStateToProps
will receive ownProps
.
If the formal definition of the function contains one mandatory parameter, mapStateToProps
will not receive ownProps
:
It will receive ownProps
when the formal definition of the function contains zero or two mandatory parameters:
Links and References
Tutorials
- Practical Redux Series, Part 6: Connected Lists, Forms, and Performance
- Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance
Performance
- Lee Byron's Tweet Suggesting to avoid
toJS
,toArray
andtoObject
for Performance - Improving React and Redux performance with Reselect
- Immutable data performance links
Q&A