Skip to content

Commit 644f4b4

Browse files
committed
add shallowEqual to React.memo as a workaround
1 parent 9ff14c1 commit 644f4b4

File tree

14 files changed

+74
-51
lines changed

14 files changed

+74
-51
lines changed

README.md

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,65 +56,65 @@ in your browser, and click the button very quickly. (check the console log)
5656

5757
```
5858
react-redux
59-
✓ check1: updated properly (3533ms)
60-
✕ check2: no tearing during update (22ms)
59+
✓ check1: updated properly (3185ms)
60+
✕ check2: no tearing during update (20ms)
6161
✓ check3: ability to interrupt render
62-
check4: proper update after interrupt (5152ms)
62+
check4: proper update after interrupt (1464ms)
6363
reactive-react-redux
64-
✓ check1: updated properly (3626ms)
64+
✓ check1: updated properly (3147ms)
6565
✓ check2: no tearing during update (1ms)
6666
✓ check3: ability to interrupt render
67-
✓ check4: proper update after interrupt (1464ms)
67+
✓ check4: proper update after interrupt (1157ms)
6868
react-tracked
69-
✓ check1: updated properly (8303ms)
69+
✓ check1: updated properly (8271ms)
7070
✓ check2: no tearing during update (1ms)
71-
✓ check3: ability to interrupt render (1ms)
72-
✓ check4: proper update after interrupt (1195ms)
71+
✓ check3: ability to interrupt render
72+
✓ check4: proper update after interrupt (1120ms)
7373
constate
74-
✓ check1: updated properly (8382ms)
74+
✓ check1: updated properly (8198ms)
7575
✓ check2: no tearing during update (1ms)
7676
✓ check3: ability to interrupt render
77-
✓ check4: proper update after interrupt (2401ms)
77+
✓ check4: proper update after interrupt (2187ms)
7878
unstated-next
79-
✓ check1: updated properly (8720ms)
79+
✓ check1: updated properly (8231ms)
8080
✓ check2: no tearing during update (1ms)
8181
✓ check3: ability to interrupt render
82-
✓ check4: proper update after interrupt (1255ms)
82+
✓ check4: proper update after interrupt (2341ms)
8383
zustand
84-
✓ check1: updated properly (3613ms)
85-
✕ check2: no tearing during update (22ms)
86-
✓ check3: ability to interrupt render (1ms)
87-
check4: proper update after interrupt (5138ms)
84+
✓ check1: updated properly (3186ms)
85+
✕ check2: no tearing during update (20ms)
86+
✓ check3: ability to interrupt render
87+
check4: proper update after interrupt (1459ms)
8888
react-sweet-state
89-
✓ check1: updated properly (9351ms)
90-
✕ check2: no tearing during update (2ms)
89+
✓ check1: updated properly (10614ms)
90+
✕ check2: no tearing during update (1ms)
9191
✕ check3: ability to interrupt render (1ms)
92-
check4: proper update after interrupt (5203ms)
92+
check4: proper update after interrupt (1092ms)
9393
storeon
94-
✓ check1: updated properly (3415ms)
94+
✓ check1: updated properly (3144ms)
9595
✕ check2: no tearing during update (20ms)
96-
✓ check3: ability to interrupt render
97-
check4: proper update after interrupt (5152ms)
96+
✓ check3: ability to interrupt render (1ms)
97+
check4: proper update after interrupt (1239ms)
9898
react-hooks-global-state
99-
✓ check1: updated properly (8967ms)
99+
✓ check1: updated properly (8592ms)
100100
✓ check2: no tearing during update (1ms)
101101
✓ check3: ability to interrupt render
102-
✓ check4: proper update after interrupt (1205ms)
102+
✓ check4: proper update after interrupt (2207ms)
103103
use-context-selector
104-
✓ check1: updated properly (8604ms)
104+
✓ check1: updated properly (8601ms)
105105
✓ check2: no tearing during update (1ms)
106106
✓ check3: ability to interrupt render
107-
✓ check4: proper update after interrupt (2246ms)
107+
✓ check4: proper update after interrupt (1100ms)
108108
mobx-react-lite
109-
check1: updated properly (11839ms)
110-
✕ check2: no tearing during update (2ms)
109+
check1: updated properly (2855ms)
110+
✕ check2: no tearing during update (1ms)
111111
✓ check3: ability to interrupt render
112-
check4: proper update after interrupt (5067ms)
112+
check4: proper update after interrupt (1156ms)
113113
use-subscription
114-
✓ check1: updated properly (8458ms)
114+
✓ check1: updated properly (8222ms)
115115
✓ check2: no tearing during update (1ms)
116116
✓ check3: ability to interrupt render
117-
check4: proper update after interrupt (5054ms)
117+
check4: proper update after interrupt (2270ms)
118118
```
119119

120120
</details>
@@ -133,7 +133,7 @@ in your browser, and click the button very quickly. (check the console log)
133133
<td>Pass</td>
134134
<td>Fail</td>
135135
<td>Pass</td>
136-
<td>Fail</td>
136+
<td>Pass</td>
137137
</tr>
138138

139139
<tr>
@@ -173,23 +173,23 @@ in your browser, and click the button very quickly. (check the console log)
173173
<td>Pass</td>
174174
<td>Fail</td>
175175
<td>Pass</td>
176-
<td>Fail</td>
176+
<td>Pass</td>
177177
</tr>
178178

179179
</tr>
180180
<th>react-sweet-state</th>
181181
<td>Pass</td>
182182
<td>Fail</td>
183-
<td>Fail? (just a little bit slow)</td>
184-
<td>Fail</td>
183+
<td>Fair (just a little bit slow)</td>
184+
<td>Pass</td>
185185
</tr>
186186

187187
</tr>
188188
<th>storeon</th>
189189
<td>Pass</td>
190190
<td>Fail</td>
191191
<td>Pass</td>
192-
<td>Fail</td>
192+
<td>Pass</td>
193193
</tr>
194194

195195
</tr>
@@ -210,18 +210,18 @@ in your browser, and click the button very quickly. (check the console log)
210210

211211
</tr>
212212
<th>mobx-react-lite</th>
213-
<td>Fail</td>
214-
<td>Fail</td>
215213
<td>Pass</td>
216214
<td>Fail</td>
215+
<td>Pass</td>
216+
<td>Pass</td>
217217
</tr>
218218

219219
</tr>
220220
<th>use-subscription (w/ redux)</th>
221221
<td>Pass</td>
222222
<td>Pass</td>
223223
<td>Pass</td>
224-
<td>Fail</td>
224+
<td>Pass</td>
225225
</tr>
226226
</table>
227227

src/common.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,14 @@ export const useCheckTearing = () => {
4545
}
4646
});
4747
};
48+
49+
// naive shallowEqual for React.memo
50+
// a hack until the issue is resolved
51+
// https://github.com/facebook/react/issues/17314
52+
// https://github.com/facebook/react/issues/17318
53+
export const shallowEqual = (prevProps, nextProps) => {
54+
const prevKeys = Object.keys(prevProps);
55+
const nextKeys = Object.keys(nextProps);
56+
return prevKeys.every(key => prevProps[key] === nextProps[key])
57+
&& nextKeys.every(key => prevProps[key] === nextProps[key]);
58+
};

src/constate/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const useValue = () => React.useReducer(reducer, initialState);
@@ -18,7 +19,7 @@ const Counter = React.memo(() => {
1819
const { count } = state;
1920
syncBlock();
2021
return <div className="count">{count}</div>;
21-
});
22+
}, shallowEqual);
2223

2324
const Main = () => {
2425
const [state, dispatch] = useValueContext();

src/mobx-react-lite/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
initialState,
88
ids,
99
useCheckTearing,
10+
shallowEqual,
1011
} from '../common';
1112

1213
const Ctx = createContext();
@@ -18,7 +19,7 @@ const Counter = React.memo(() => {
1819
syncBlock();
1920
return <div className="count">{count}</div>;
2021
});
21-
});
22+
}, shallowEqual);
2223

2324
const Main = () => {
2425
const store = useContext(Ctx);

src/react-hooks-global-state/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const { GlobalStateProvider, dispatch, useGlobalState } = createStore(reducer, initialState);
@@ -16,7 +17,7 @@ const Counter = React.memo(() => {
1617
const [count] = useGlobalState('count');
1718
syncBlock();
1819
return <div className="count">{count}</div>;
19-
});
20+
}, shallowEqual);
2021

2122
const Main = () => {
2223
const [count] = useGlobalState('count');

src/react-redux/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const store = createStore(reducer);
@@ -16,7 +17,7 @@ const Counter = React.memo(() => {
1617
const count = useSelector(state => state.count);
1718
syncBlock();
1819
return <div className="count">{count}</div>;
19-
});
20+
}, shallowEqual);
2021

2122
const Main = () => {
2223
const dispatch = useDispatch();

src/react-sweet-state/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const Store = createStore({
@@ -26,7 +27,7 @@ const Counter = React.memo(() => {
2627
const { count } = state;
2728
syncBlock();
2829
return <div className="count">{count}</div>;
29-
});
30+
}, shallowEqual);
3031

3132
const Main = () => {
3233
const [state, actions] = useCounter();

src/react-tracked/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const useValue = () => React.useReducer(reducer, initialState);
@@ -18,7 +19,7 @@ const Counter = React.memo(() => {
1819
const count = useSelector(state => state.count);
1920
syncBlock();
2021
return <div className="count">{count}</div>;
21-
});
22+
}, shallowEqual);
2223

2324
const Main = () => {
2425
const dispatch = useDispatch();

src/reactive-react-redux/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const store = createStore(reducer);
@@ -16,7 +17,7 @@ const Counter = React.memo(() => {
1617
const count = useSelector(state => state.count);
1718
syncBlock();
1819
return <div className="count">{count}</div>;
19-
});
20+
}, shallowEqual);
2021

2122
const Main = () => {
2223
const dispatch = useDispatch();

src/storeon/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
reducer,
1111
ids,
1212
useCheckTearing,
13+
shallowEqual,
1314
} from '../common';
1415

1516
const counter = (store) => {
@@ -23,7 +24,7 @@ const Counter = React.memo(() => {
2324
const { count } = useStoreon('count');
2425
syncBlock();
2526
return <div className="count">{count}</div>;
26-
});
27+
}, shallowEqual);
2728

2829
const Main = () => {
2930
const { count, dispatch } = useStoreon('count');

src/unstated-next/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const useValue = () => React.useReducer(reducer, initialState);
@@ -18,7 +19,7 @@ const Counter = React.memo(() => {
1819
const { count } = state;
1920
syncBlock();
2021
return <div className="count">{count}</div>;
21-
});
22+
}, shallowEqual);
2223

2324
const Main = () => {
2425
const [state, dispatch] = C.useContainer();

src/use-context-selector/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const context = createContext(null);
@@ -25,7 +26,7 @@ const Counter = React.memo(() => {
2526
const count = useContextSelector(context, v => v[0].count);
2627
syncBlock();
2728
return <div className="count">{count}</div>;
28-
});
29+
}, shallowEqual);
2930

3031
const Main = () => {
3132
const dispatch = useContextSelector(context, v => v[1]);

src/use-subscription/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const store = createStore(reducer);
@@ -21,7 +22,7 @@ const Counter = React.memo(() => {
2122
}), []));
2223
syncBlock();
2324
return <div className="count">{count}</div>;
24-
});
25+
}, shallowEqual);
2526

2627
const Main = () => {
2728
const count = useSubscription(React.useMemo(() => ({

src/zustand/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
reducer,
99
ids,
1010
useCheckTearing,
11+
shallowEqual,
1112
} from '../common';
1213

1314
const [useStore] = create(set => ({
@@ -19,7 +20,7 @@ const Counter = React.memo(() => {
1920
const count = useStore(state => state.count);
2021
syncBlock();
2122
return <div className="count">{count}</div>;
22-
});
23+
}, shallowEqual);
2324

2425
const Main = () => {
2526
const count = useStore(state => state.count);

0 commit comments

Comments
 (0)