Skip to content

Commit ced8c70

Browse files
committed
why reducer need to be pure function
1 parent f377cfc commit ced8c70

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed
+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#### As a side note - Redux need reducers to be “pure functions
2+
13
#### Basic example of mutations
24

35
```js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#### Lets look at the Redux Source Code
2+
3+
[https://github.com/reduxjs/redux/blob/9d3273846aa8906d38890c410b62fb09a4992018/src/combineReducers.ts#L197](https://github.com/reduxjs/redux/blob/9d3273846aa8906d38890c410b62fb09a4992018/src/combineReducers.ts#L197)
4+
5+
```js
6+
let hasChanged = false
7+
const nextState: StateFromReducersMapObject<typeof reducers> = {}
8+
for (let i = 0; i < finalReducerKeys.length; i++) {
9+
const key = finalReducerKeys[i]
10+
const reducer = finalReducers[key]
11+
const previousStateForKey = state[key]
12+
const nextStateForKey = reducer(previousStateForKey, action)
13+
if (typeof nextStateForKey === 'undefined') {
14+
const errorMessage = getUndefinedStateErrorMessage(key, action)
15+
throw new Error(errorMessage)
16+
}
17+
nextState[key] = nextStateForKey
18+
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
19+
}
20+
hasChanged =
21+
hasChanged || finalReducerKeys.length !== Object.keys(state).length
22+
return hasChanged ? nextState : state
23+
}
24+
25+
```
26+
27+
The line `const nextStateForKey = reducer(previousStateForKey, action)` >> Redux takes a given state (object) and passes it to each reducer in a loop. And it expects a brand new object from the reducer if there are any changes. And it also expects to get the old object back if there are no changes.
28+
29+
The line `hasChanged = hasChanged || nextStateForKey !== previousStateForKey` >> **Redux simply checks whether the old object is the same as the new object by comparing the memory locations of the two objects. NOT BY DEEP-COMPARING THE PROPS - So if you mutate the old object’s property inside a reducer, the “new state” and the “old state” will both point to the same object. Hence Redux thinks nothing has changed! So this won’t work.**
30+
31+
But, it still doesn’t answer some key questions like:
32+
33+
Why is Redux designed like this?
34+
Why can’t Redux just make a copy of the old state some place else, then compare object props from reducers?
35+
Why is Redux putting this burden on individual developers?
36+
37+
#### The answer: there is only one way to know if two JavaScript objects have the same properties. To deep-compare them.
38+
39+
#### But this becomes extremely expensive in real-world apps, because of the typically large objects and the number of times they need to be compared.
40+
41+
#### So one work around is to have a policy to ask developers to create a new object whenever there is a change, then send it to the framework. And if there are no changes, then send back the old object as it is. In other words, new objects represent new states.
42+
43+
Note that you must clone old states using slice — or a similar mechanism — to copy old values into a new object.
44+
45+
Now, with this policy in place, you can compare two objects’ memory location using !== without having to compare each property within each object. And if the two objects are not the same, then you know that the object has changed state (that is, some property somewhere in the JavaScript object has changed). That’s exactly the strategy Redux employs to make things work.
46+
47+
So that’s why Redux needs for “Reducers” to be pure functions!
48+
49+
Per [Redux Official Doc on Shallow Equality Checking](https://redux.js.org/faq/immutable-data#why-does-reduxs-use-of-shallow-equality-checking-require-immutability)
50+
51+
Why does Redux’s use of shallow equality checking require immutability?
52+
Redux's use of shallow equality checking requires immutability if any connected components are to be updated correctly. To see why, we need to understand the difference between shallow and deep equality checking in JavaScript.
53+
54+
How do shallow and deep equality checking differ?
55+
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.
56+
57+
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.
58+
59+
It's for this improvement in performance that Redux uses shallow equality checking.
60+
61+
#### Further Reading
62+
63+
[https://www.freecodecamp.org/news/why-redux-needs-reducers-to-be-pure-functions-d438c58ae468/](https://www.freecodecamp.org/news/why-redux-needs-reducers-to-be-pure-functions-d438c58ae468/)

0 commit comments

Comments
 (0)