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
Copy file name to clipboardExpand all lines: docs/faq/ImmutableData.md
+73-75Lines changed: 73 additions & 75 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -63,7 +63,7 @@ Redux's use of shallow equality checking requires immutability if any connected
63
63
### How do shallow and deep equality checking differ?
64
64
Shallow equality checking (or _reference equality_) simply checks that two different _variables_ reference the same object; in contrast, deep equality checking (or _value equality_) must check every _value_ of two objects' properties.
65
65
66
-
A shallow equality check is therefore as simple (and as fast) as `a === b`, whereas a deep equality check involves a recursive traversal through the properties of two objects, comparing the value of each property at each step.
66
+
A shallow equality check is therefore as simple (and as fast) as `a === b`, whereas a deep equality check involves a recursive traversal through the properties of two objects, comparing the value of each property at each step.
67
67
68
68
It's for this improvement in performance that Redux uses shallow equality checking.
69
69
@@ -90,8 +90,8 @@ The [suggested structure](http://redux.js.org/docs/faq/Reducers.html#reducers-sh
90
90
`combineReducers` makes working with this style of structure easier by taking a `reducers` argument that’s defined as a hash table comprising a set of key/value pairs, where each key is the name of a state slice, and the corresponding value is the reducer function that will act on it.
91
91
92
92
So, for example, if your state shape is `{ todos, counter }`, the call to `combineReducers` would be:
As it continues through the iterations, `combineReducers` will construct a new state object with the state slices returned from each reducer. This new state object may or may not be different from the current state object. It is here that `combineReducers` uses shallow equality checking to determine whether the state has changed.
107
107
108
-
Specifically, at each stage of the iteration, `combineReducers` performs a shallow equality check on the current state slice and the state slice returned from the reducer. If the reducer returns a new object, the shallow equality check will fail, and `combineReducers` will set a `hasChanged` flag to true.
108
+
Specifically, at each stage of the iteration, `combineReducers` performs a shallow equality check on the current state slice and the state slice returned from the reducer. If the reducer returns a new object, the shallow equality check will fail, and `combineReducers` will set a `hasChanged` flag to true.
109
109
110
110
After the iterations have completed, `combineReducers` will check the state of the `hasChanged` flag. If it’s true, the newly-constructed state object will be returned. If it’s false, the _current_ state object is returned.
111
111
@@ -148,20 +148,20 @@ React-Redux performs a shallow equality check on on each _value_ within the prop
148
148
149
149
It does so because the props object is actually a hash of prop names and their values (or selector functions that are used to retrieve or generate the values), such as in this example:
150
150
151
-
```
151
+
```js
152
152
functionmapStateToProps(state) {
153
-
return {
154
-
todos: state.todos, // prop value
155
-
visibleTodos: getVisibleTodos(state) // selector
156
-
}
153
+
return {
154
+
todos:state.todos, // prop value
155
+
visibleTodos:getVisibleTodos(state) // selector
156
+
}
157
157
}
158
158
159
159
exportdefaultconnect(mapStateToProps)(TodoApp)
160
160
```
161
161
162
162
As such, a shallow equality check of the props object returned from repeated calls to `mapStateToProps` would always fail, as a new object would be returned each time.
163
163
164
-
React-Redux therefore maintains separate references to each _value_ in the returned props object.
164
+
React-Redux therefore maintains separate references to each _value_ in the returned props object.
165
165
166
166
#### Further Information
167
167
@@ -173,35 +173,35 @@ React-Redux therefore maintains separate references to each _value_ in the retur
173
173
### How does React-Redux use shallow equality checking to determine whether a component needs re-rendering?
174
174
Each time React-Redux’s `connect` function is called, it will perform a shallow equality check on its stored reference to the root state object, and the current root state object passed to it from the store. If the check passes, the root state object has not been updated, and so there is no need to re-render the component, or even call `mapStateToProps`.
175
175
176
-
If the check fails, however, the root state object _has_ been updated, and so `connect` will call `mapStateToProps`to see if the props for the wrapped component have been updated.
176
+
If the check fails, however, the root state object _has_ been updated, and so `connect` will call `mapStateToProps`to see if the props for the wrapped component have been updated.
177
177
178
178
It does this by performing a shallow equality check on each value within the object individually, and will only trigger a re-render if one of those checks fails.
179
179
180
180
In the example below, if `state.todos` and the value returned from `getVisibleTodos()` do not change on successive calls to `connect`, then the component will not re-render .
181
181
182
-
```
182
+
```js
183
183
functionmapStateToProps(state) {
184
-
return {
185
-
todos: state.todos, // prop value
186
-
visibleTodos: getVisibleTodos(state) // selector
187
-
}
184
+
return {
185
+
todos:state.todos, // prop value
186
+
visibleTodos:getVisibleTodos(state) // selector
187
+
}
188
188
}
189
189
190
190
exportdefaultconnect(mapStateToProps)(TodoApp)
191
191
```
192
192
193
193
Conversely, in this next example (below), the component will _always_ re-render, as the value of `todos` is always a new object, regardless of whether or not its values change:
194
194
195
-
```
195
+
```js
196
196
// AVOID - will always cause a re-render
197
197
functionmapStateToProps(state) {
198
-
return {
199
-
// todos always references a newly-created object
200
-
todos: {
201
-
all: state.todos,
202
-
visibleTodos: getVisibleTodos(state)
203
-
}
204
-
}
198
+
return {
199
+
// todos always references a newly-created object
200
+
todos: {
201
+
all:state.todos,
202
+
visibleTodos:getVisibleTodos(state)
203
+
}
204
+
}
205
205
}
206
206
207
207
exportdefaultconnect(mapStateToProps)(TodoApp)
@@ -228,16 +228,16 @@ Shallow equality checking cannot be used to detect if a function mutates an obje
228
228
This is because two variables that reference the same object will _always_ be equal, regardless of whether the object’s values changes or not, as they're both referencing the same object. Thus, the following will always return true:
229
229
230
230
231
-
```
231
+
```js
232
232
functionmutateObj(obj) {
233
-
obj.key = 'newValue';
234
-
return obj;
233
+
obj.key='newValue'
234
+
return obj
235
235
}
236
236
237
-
const param = { key: 'originalValue' };
238
-
const returnVal = mutateObj(param);
237
+
constparam= { key:'originalValue' }
238
+
constreturnVal=mutateObj(param)
239
239
240
-
param === returnVal;
240
+
param === returnVal
241
241
//> true
242
242
```
243
243
@@ -254,7 +254,7 @@ The shallow check of `param` and `returnValue` simply checks whether both variab
254
254
### Does shallow equality checking with a mutable object cause problems with Redux?
255
255
Shallow equality checking with a mutable object will not cause problems with Redux, but [it will cause problems with libraries that depend on the store, such as React-Redux](#shallow-checking-problems-with-react-redux).
256
256
257
-
Specifically, if the state slice passed to a reducer by `combineReducers` is a mutable object, the reducer can modify it directly and return it.
257
+
Specifically, if the state slice passed to a reducer by `combineReducers` is a mutable object, the reducer can modify it directly and return it.
258
258
259
259
If it does, the shallow equality check that `combineReducers` performs will always pass, as the values of the state slice returned by the reducer may have been mutated, but the object itself has not - it’s still the same object that was passed to the reducer.
260
260
@@ -289,37 +289,35 @@ As we’ve seen, the values in the mutable object returned by the selector funct
289
289
290
290
For example, the following `mapStateToProps` function will never trigger a re-render:
291
291
292
-
```
292
+
```js
293
293
// State object held in the Redux store
294
294
conststate= {
295
-
user: {
296
-
accessCount: 0,
297
-
name: 'keith'
298
-
}
299
-
};
295
+
user: {
296
+
accessCount:0,
297
+
name:'keith'
298
+
}
299
+
}
300
300
301
301
// Selector function
302
-
const getUser = (state) => {
303
-
++state.user.accessCount; // mutate the state object
304
-
return state;
302
+
constgetUser=state=> {
303
+
++state.user.accessCount// mutate the state object
304
+
return state
305
305
}
306
306
307
307
// mapStateToProps
308
-
const mapStateToProps = (state) => ({
309
-
// The object returned from getUser() is always
310
-
// the same object, so this wrapped
311
-
// component will never re-render, even though it's been
312
-
// mutated
313
-
userRecord: getUser(state)
314
-
});
315
-
308
+
constmapStateToProps=state=> ({
309
+
// The object returned from getUser() is always
310
+
// the same object, so this wrapped
311
+
// component will never re-render, even though it's been
312
+
// mutated
313
+
userRecord:getUser(state)
314
+
})
316
315
317
-
const a = mapStateToProps(state);
318
-
const b = mapStateToProps(state);
316
+
consta=mapStateToProps(state)
317
+
constb=mapStateToProps(state)
319
318
320
-
a.userRecord === b.userRecord;
319
+
a.userRecord===b.userRecord
321
320
//> true
322
-
323
321
```
324
322
325
323
Note that, conversely, if an _immutable_ object is used, the [component may re-render when it should not](#immutability-issues-with-react-redux).
@@ -335,7 +333,7 @@ Note that, conversely, if an _immutable_ object is used, the [component may re-r
335
333
336
334
<aid="immutability-enables-shallow-checking"></a>
337
335
### How does immutability enable a shallow check to detect object mutations?
338
-
If an object is immutable, any changes that need to be made to it within a function must be made to a _copy_ of the object.
336
+
If an object is immutable, any changes that need to be made to it within a function must be made to a _copy_ of the object.
339
337
340
338
This mutated copy is a _separate_ object from that passed into the function, and so when it is returned, a shallow check will identify it as being a different object from that passed in, and so will fail.
341
339
@@ -366,17 +364,17 @@ To prevent this from happening, you must *always return the state slice object t
366
364
### How can immutability in `mapStateToProps` cause components to render unnecessarily?
367
365
Certain immutable operations, such as an Array filter, will always return a new object, even if the values themselves have not changed.
368
366
369
-
If such an operation is used as a selector function in `mapStateToProps`, the shallow equality check that React-Redux performs on each value
367
+
If such an operation is used as a selector function in `mapStateToProps`, the shallow equality check that React-Redux performs on each value
370
368
in the props object that’s returned will always fail, as the selector is returning a new object each time.
371
369
372
-
As such, even though the values of that new object have not changed, the wrapped component will always be re-rendered,
370
+
As such, even though the values of that new object have not changed, the wrapped component will always be re-rendered,
373
371
374
372
For example, the following will always trigger a re-render:
375
373
376
-
```
374
+
```js
377
375
// A JavaScript array's 'filter' method treats the array as immutable,
// getVisibleTodos() always returns a new array, and so the
396
-
// 'visibleToDos' prop will always reference a different array,
397
-
// causing the wrapped component to re-render, even if the array's
398
-
// values haven't changed
399
-
visibleToDos: getVisibleTodos(state.todos)
391
+
392
+
constmapStateToProps=state=> ({
393
+
// getVisibleTodos() always returns a new array, and so the
394
+
// 'visibleToDos' prop will always reference a different array,
395
+
// causing the wrapped component to re-render, even if the array's
396
+
// values haven't changed
397
+
visibleToDos:getVisibleTodos(state.todos)
400
398
})
401
399
402
-
const a = mapStateToProps(state);
400
+
consta=mapStateToProps(state)
403
401
// Call mapStateToProps(state) again with exactly the same arguments
404
-
const b = mapStateToProps(state);
402
+
constb=mapStateToProps(state)
405
403
406
-
a.visibleToDos;
404
+
a.visibleToDos
407
405
//> { "completed": false, "text": "do todo 1" }
408
406
409
-
b.visibleToDos;
407
+
b.visibleToDos
410
408
//> { "completed": false, "text": "do todo 1" }
411
409
412
-
a.visibleToDos === b.visibleToDos;
410
+
a.visibleToDos===b.visibleToDos
413
411
//> false
414
412
```
415
413
@@ -425,8 +423,8 @@ Note that, conversely, if the values in your props object refer to mutable objec
425
423
426
424
427
425
<aid="do-i-have-to-use-immutable-js"></a>
428
-
## What approaches are there for handling data immutably? Do I have to use Immutable.JS?
429
-
You do not need to use Immutable.JS with Redux. Plain JavaScript, if written correctly, is perfectly capable of providing immutability without having to use an immutable-focused library.
426
+
## What approaches are there for handling data immutably? Do I have to use Immutable.JS?
427
+
You do not need to use Immutable.JS with Redux. Plain JavaScript, if written correctly, is perfectly capable of providing immutability without having to use an immutable-focused library.
430
428
431
429
However, guaranteeing immutability with JavaScript is difficult, and it can be easy to mutate an object accidentally, causing bugs in your app that are extremely difficult to locate. For this reason, using an immutable update utility library such as Immutable.JS can significantly improve the reliability of your app, and make your app’s development much easier.
432
430
@@ -442,7 +440,7 @@ However, guaranteeing immutability with JavaScript is difficult, and it can be e
442
440
JavaScript was never designed to provide guaranteed immutable operations. Accordingly, there are several issues you need to be aware of if you choose to use it for your immutable operations in your Redux app.
443
441
444
442
### Accidental Object Mutation
445
-
With JavaScript, you can accidentally mutate an object (such as the Redux state tree) quite easily without realising it. For example, updating deeply nested properties, creating a new *reference* to an object instead of a new object, or performing a shallow copy rather than a deep copy, can all lead to inadvertent object mutations, and can trip up even the most experienced JavaScript coder.
443
+
With JavaScript, you can accidentally mutate an object (such as the Redux state tree) quite easily without realising it. For example, updating deeply nested properties, creating a new *reference* to an object instead of a new object, or performing a shallow copy rather than a deep copy, can all lead to inadvertent object mutations, and can trip up even the most experienced JavaScript coder.
446
444
447
445
To avoid these issues, ensure you follow the recommended [immutable update patterns for ES6](http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html).
Copy file name to clipboardExpand all lines: docs/faq/ReactRedux.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -51,7 +51,7 @@ Note that “updating data immutably” does *not* mean that you must use [Immut
51
51
React Redux implements several optimizations to ensure your actual component only re-renders when actually necessary. One of those is a shallow equality check on the combined props object generated by the `mapStateToProps` and `mapDispatchToProps` arguments passed to `connect`. Unfortunately, shallow equality does not help in cases where new array or object instances are created each time `mapStateToProps` is called. A typical example might be mapping over an array of IDs and returning the matching object references, such as:
0 commit comments