You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -16,106 +16,116 @@ As the first argument passed in to `connect`, `mapStateToProps` is used for sele
16
16
17
17
`mapStateToProps` should be defined as a function:
18
18
19
-
```jsx
20
-
functionmapStateToProps(state[, ownProps])
19
+
```js
20
+
functionmapStateToProps(state, ownProps?)
21
21
```
22
22
23
-
It should take `state`, optionally `ownProps`, and return a plain object containing the data that the connected component needs.
23
+
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.
24
+
25
+
This function should be passed as the first argument to `connect`, and will be 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`.
26
+
27
+
**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.
24
28
25
29
### Arguments
26
30
27
-
- `state`
31
+
#### `state`
32
+
33
+
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".)
28
34
29
-
The `mapStateToProps` function should always be written with at least `state` passed in. It will be called every time when the store changes. If you do not wish to subscribe to the store, pass `null` or `undefined` to `connect` in place of `mapStateToProps`.
35
+
The `mapStateToProps` function should always be written with at least `state` passed in.
30
36
31
-
```jsx
37
+
```js
32
38
// TodoList.js
33
-
// ...
34
39
35
-
const mapStateToProps = state => {
40
+
functionmapStateToProps(state) {
36
41
const { todos } = state;
37
42
return { todoList:todos.allIds };
38
43
};
39
44
40
45
exportdefaultconnect(mapStateToProps)(TodoList);
41
46
```
42
47
43
-
-`ownProps` (optional)
48
+
####`ownProps` (optional)
44
49
45
-
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.
50
+
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`.
46
51
47
-
```jsx
52
+
```js
48
53
// Todo.js
49
54
50
-
constmapStateToProps=(state, ownProps)=> {
55
+
functionmapStateToProps(state, ownProps) {
51
56
const { visibilityFilter } = state;
52
57
const { id } = ownProps;
53
58
consttodo=getTodoById(state, id);
54
59
55
60
// component receives additionally:
56
61
return { todo, visibilityFilter };
57
62
};
63
+
64
+
// Later, in your application, a parent component renders:
65
+
<ConnectedTodo id=123} />
66
+
// and your component receives props.id, props.todo, and props.visibilityFilter
58
67
```
59
68
60
-
**The arity of `mapStateToProps` affects its behavior:**
69
+
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.
70
+
71
+
### Return
61
72
62
-
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 when the wrapper props have changed.
73
+
Your `mapStateToProps`function should return a plain object that contains the data the component needs:
63
74
64
-
**Mandatory number of arguments determines whether `mapStateToProps` will receive `ownProps`:**
75
+
- Each field in the object will become a prop for your actual component
76
+
- The values in the fields will be used to determine if your component needs to re-render
65
77
66
-
If the formal definition of the function contains one mandatory parameter, `mapStateToProps` will _not_ receive `ownProps`:
78
+
For example:
67
79
68
-
```jsx
80
+
```js
69
81
functionmapStateToProps(state) {
70
-
console.log(state); // state
71
-
console.log(arguments[1]); // undefined
72
-
}
73
-
constmapStateToProps= (state, ownProps= {}) => {
74
-
console.log(state); // state
75
-
console.log(ownProps); // undefined
82
+
return {
83
+
a :42,
84
+
todos :state.todos,
85
+
filter :state.visibilityFilter
86
+
}
76
87
}
88
+
89
+
// component will receive: props.a, props.todos, and props.filter
77
90
```
78
91
79
-
It _will_ receive `ownProps` when the formal definition of the function contains zero or two mandatory parameters:
80
92
81
-
```jsx
82
-
constmapStateToProps= (state, ownProps) => {
83
-
console.log(state); // state
84
-
console.log(ownProps); // ownProps
85
-
}
93
+
> 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 final `mapStateToProps` 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](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds. Most apps never need this.
86
94
87
-
functionmapStateToProps() {
88
-
console.log(arguments[0]); // state
89
-
console.log(arguments[1]); // ownProps
90
-
}
91
95
92
-
constmapStateToProps= (...args) => {
93
-
console.log(args[0]); // state
94
-
console.log(args[1]); // ownProps
95
-
}
96
-
```
96
+
## Usage Guidelines
97
97
98
-
### Return
99
-
In the most common usages, you should let your `mapStateToProps` return a plain object that contains the data the component needs:
100
98
101
-
- it will be merged into the component’s props
102
-
- it will be used to decide whether the component will re-render
99
+
### Let `mapStateToProps` Reshape the Data from the Store
103
100
101
+
`mapStateToProps` functions can, and should, do a lot more than just `returnstate.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.
104
102
105
-
> 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 `mapStateToProps` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this.
106
103
107
-
React-Redux internally implements the `shouldComponentUpdate` method such that the wrapper component re-renders precisely when the data it needs change. By default, React-Redux decides whether the contents of the object returned from `mapStateToProps` are different using `===` comparison on each fields of the returned object. Returning a mutated object of the same reference is a common mistake resulting in component not re-rendering when expected.
104
+
### Use Selector Functions to Extract and Transform Data
108
105
109
-
However, if `mapStateToProps` is written in such way that it returns a different copy of the data each time, the component may re-render too many times:
106
+
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.)
107
+
108
+
109
+
### `mapStateToProps` Functions Should Be Fast
110
+
111
+
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.
112
+
113
+
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.
114
+
115
+
116
+
### `mapStateToProps` Functions Should Be Pure and Synchronous
117
+
118
+
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`.
119
+
120
+
121
+
122
+
## `mapStateToProps` and Performance
123
+
124
+
125
+
### Return Values Determine If Your Component Re-Renders
126
+
127
+
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.
110
128
111
-
```jsx
112
-
constmapStateToProps=state=> {
113
-
// re-renders even if the list may remain the same
To summarize the behavior of the component wrapped by `connect` with `mapStateToProps` to extract data from the store:
121
131
@@ -124,86 +134,97 @@ To summarize the behavior of the component wrapped by `connect` with `mapStateTo
124
134
| `mapStateToProps` runs when: | store `state` is `===` different | store `state` changes <br /> or <br />any field of `ownProps` is different |
125
135
| component re-renders when: | any field of `stateProps` is different | any field of `stateProps` is different <br /> or <br /> any field of `ownProps` is different |
126
136
127
-
New CodeSandbox [here](https://codesandbox.io/s/yvvqxj4p11):
128
137
129
-
-`TodoList` now connects to `todos.allIds`
130
-
-`Todo` connects to `todos.byIds` with `id` from `ownProps`, and gets `visibilityFilter`
131
-
-`Todo` contains a simpler filter in itself to determine whether to show or hide each todo
132
-
- a bunch of commented out console logs to play around and see how the component behaves
138
+
### Only Return New Object References If Needed
133
139
140
+
React-Redux does shallow comparisons to see if the `mapState` 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.
134
141
135
-
## Keys to Good Redux Performance
142
+
Many common operations result in new object or array references being created:
136
143
137
-
### `mapStateToProps` Functions Should Be Fast
144
+
- Creating new arrays with `someArray.map()` or `someArray.filter()`
145
+
- Merging arrays with `array.concat`
146
+
- Copying values with `Object.assign`
147
+
- Copying values with the spread operator `{ ...oldState, ...newData }`
138
148
139
-
Whenever the store changes, all of the `mapStateToProps`functions of all of the connected components will run. That is a lot of callings of `mapStateToProps` at a very high frequency. `mapStateToProps` should be fast.
149
+
Put these operation in [memoized selector functions]() to ensure that they only run if the input values have changed.
140
150
141
-
Avoid doing very expensive work in `mapStateToProps` unless absolutely necessary. This includes:
142
151
143
-
**Complex filtering and transformations**
144
152
145
-
You will probably need to do complex transformations at some point. Consider first whether the transformation fits better in another place:
153
+
### Only Perform Expensive Operations When Data Changes
146
154
147
-
- Reducer is a potentially better candidate, because it concerns its own related data.
148
-
- Component’s lifecycle events such as `componentDidUpdate` or `render`, because their number of calls are cut down by `mapStateToProps` functions.
149
-
- If `mapStateToProps` is unavoidably the most suitable place for some costly computations, we suggest using memoized selectors. You may refer to the links at the end of this section for more information.
155
+
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.
150
156
151
-
**Expensive functions such as `toJS()` of `Immutable.js`**
157
+
There are a few ways to approach this:
152
158
153
-
[Immutable.js author Lee Byron on Twitter](https://twitter.com/leeb/status/746733697093668864?lang=en) explicitly advises avoiding `toJS` when performance is a concern:
159
+
- Some transformations could be calculated in an action creator or reducer, and the transformed data could be kept in the store
160
+
- Transformations can also be done in a component's `render()` method
161
+
- 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.
162
+
163
+
164
+
#### Immutable.js Performance Concerns
165
+
166
+
Immutable.js author Lee Byron on Twitter [explicitly advises avoiding `toJS` when performance is a concern](https://twitter.com/leeb/status/746733697093668864?lang=en):
154
167
155
168
> Perf tip for #immutablejs: avoid .toJS() .toObject() and .toArray() all slow full-copy operations which render structural sharing useless.
156
169
157
-
There's several other performance concerns to take into consideration with Immutable.js - see the list of links at the end of this post for more information.
170
+
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.
158
171
159
-
**Await async function calls**
160
172
161
-
A `mapStateToProps` function should be pure and 100% synchronous, like a reducer — state (+ownProps) in, resulting props out.
162
-
No AJAX calls, no async stuff, no dispatching actions.
163
173
164
-
### Let `mapStateToProps` Reshape the Data from the Store
174
+
## Behavior and Gotchas
165
175
166
-
`mapStateToProps` functions can, and should, do a lot more than just `return state.someSlice`.
167
-
They have the responsibility of "re-shaping" store data as needed for that component.
168
-
However, such computations should subject to its own performance requirement mentioned above.
169
176
170
-
### Do Not Return New References of Objects
177
+
### `mapStateToProps` Will Not Run if the Store State is the Same
171
178
172
-
To avoid unnecessary re-rendering, do not return new references of objects.
179
+
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.
173
180
174
-
Whenever the store state changes, all connected components will receive the updated store state and run `mapStateToProps` functions with them.
175
-
Odds are the changes happen only to a small slice of the store, and unrelated components should just receive the same data.
181
+
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.
176
182
177
-
React-Redux does those shallow comparisons to avoid unnecessary re-rendering.
178
-
However, 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.
179
183
180
-
Some examples are:
181
184
182
-
- Mapping over arrays `array.map`
183
-
- Merging arrays with `array.concat`
184
-
- Copying values with `Object.assign`
185
-
- Copying values with the spread operator `{ ...oldState, ...newData }`
185
+
### The Number of Declared Arguments Affects Behavior
186
186
187
-
In `mapState` functions, it suffices to use the dot accessor for object values
187
+
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.
188
188
189
-
```jsx
190
-
constmapStateToProps=state=> {
191
-
// destructuring is ok
192
-
const { todos } = state;
193
-
return {
194
-
// do this:
195
-
user:state.user,
196
-
todos,
197
-
}
189
+
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.
190
+
191
+
192
+
There are some edge cases around this behavior. **The number of mandatory arguments determines whether `mapStateToProps` will receive `ownProps`**.
193
+
194
+
If the formal definition of the function contains one mandatory parameter, `mapStateToProps` will _not_ receive `ownProps`:
195
+
196
+
```js
197
+
functionmapStateToProps(state) {
198
+
console.log(state); // state
199
+
console.log(arguments[1]); // undefined
200
+
}
201
+
constmapStateToProps= (state, ownProps= {}) => {
202
+
console.log(state); // state
203
+
console.log(ownProps); // undefined
204
+
}
205
+
```
206
+
207
+
It _will_ receive `ownProps` when the formal definition of the function contains zero or two mandatory parameters:
208
+
209
+
```js
210
+
functionmapStateToProps(state, ownProps) {
211
+
console.log(state); // state
212
+
console.log(ownProps); // ownProps
213
+
}
214
+
215
+
functionmapStateToProps() {
216
+
console.log(arguments[0]); // state
217
+
console.log(arguments[1]); // ownProps
218
+
}
219
+
220
+
functionmapStateToProps(...args) {
221
+
console.log(args[0]); // state
222
+
console.log(args[1]); // ownProps
198
223
}
199
224
```
200
225
201
-
### Connect More Components
202
226
203
-
Overall performance is a balance between the overhead of more `mapStateToProps` calls, and time spent by React re-rendering.
204
-
Redux subscriptions are O(n) - every additional subscriber means a bit more work every time an action is dispatched.
205
-
Fortunately, benchmarks have shown that the cost of more connected components is generally less than the cost of more wasted re-rendering.
206
-
See this FAQ ["Should I only connect my top component, or can I connect multiple components in my tree?"](https://redux.js.org/faq/reactredux#react-multiple-components) for more discussions.
227
+
207
228
208
229
<!--
209
230
## Next Up
@@ -217,12 +238,13 @@ See this FAQ ["Should I only connect my top component, or can I connect multiple
217
238
**Tutorials**
218
239
219
240
- [Practical Redux Series, Part 6: Connected Lists, Forms, and Performance](https://blog.isquaredsoftware.com/2017/01/practical-redux-part-6-connected-lists-forms-and-performance/)
241
+
- [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/)
220
242
221
243
**Performance**
222
244
223
245
- [Lee Byron's Tweet Suggesting to avoid `toJS`, `toArray` and `toObject` for Performance](https://twitter.com/leeb/status/746733697093668864)
224
246
- [Improving React and Redux performance with Reselect](https://blog.rangle.io/react-and-redux-performance-with-reselect/)
225
-
-[Relevant links to immutable data](https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#immutable-data)
247
+
- [Immutable data performance links](https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#immutable-data)
0 commit comments