@@ -14,7 +14,7 @@ let previousInternal;
14
14
/** @type {number } */
15
15
let currentHook = 0 ;
16
16
17
- /** @type {Array<import('./internal').Component > } */
17
+ /** @type {Array<import('./internal').Internal > } */
18
18
let afterPaintEffects = [ ] ;
19
19
20
20
let EMPTY = [ ] ;
@@ -180,16 +180,49 @@ export function useReducer(reducer, initialState, init) {
180
180
] ;
181
181
182
182
hookState . _internal = currentInternal ;
183
- currentInternal . _component . shouldComponentUpdate = ( ) => {
184
- if ( ! hookState . _nextValue ) return true ;
185
-
186
- const currentValue = hookState . _value [ 0 ] ;
187
- hookState . _value = hookState . _nextValue ;
188
- hookState . _nextValue = undefined ;
189
-
190
- return currentValue !== hookState . _value [ 0 ] ;
191
- } ;
183
+ if ( ! currentInternal . data . _hasScuFromHooks ) {
184
+ currentInternal . data . _hasScuFromHooks = true ;
185
+ const prevScu = currentInternal . _component . shouldComponentUpdate ;
186
+
187
+ // This SCU has the purpose of bailing out after repeated updates
188
+ // to stateful hooks.
189
+ // we store the next value in _nextValue[0] and keep doing that for all
190
+ // state setters, if we have next states and
191
+ // all next states within a component end up being equal to their original state
192
+ // we are safe to bail out for this specific component.
193
+ currentInternal . _component . shouldComponentUpdate = function ( p , s , c ) {
194
+ if ( ! hookState . _internal . data . __hooks ) return true ;
195
+
196
+ const stateHooks = hookState . _internal . data . __hooks . _list . filter (
197
+ x => x . _internal
198
+ ) ;
199
+ const allHooksEmpty = stateHooks . every ( x => ! x . _nextValue ) ;
200
+ // When we have no updated hooks in the component we invoke the previous SCU or
201
+ // traverse the VDOM tree further.
202
+ if ( allHooksEmpty ) {
203
+ return prevScu ? prevScu . call ( this , p , s , c ) : true ;
204
+ }
192
205
206
+ // We check whether we have components with a nextValue set that
207
+ // have values that aren't equal to one another this pushes
208
+ // us to update further down the tree
209
+ let shouldUpdate = false ;
210
+ stateHooks . forEach ( hookItem => {
211
+ if ( hookItem . _nextValue ) {
212
+ const currentValue = hookItem . _value [ 0 ] ;
213
+ hookItem . _value = hookItem . _nextValue ;
214
+ hookItem . _nextValue = undefined ;
215
+ if ( currentValue !== hookItem . _value [ 0 ] ) shouldUpdate = true ;
216
+ }
217
+ } ) ;
218
+
219
+ return shouldUpdate
220
+ ? prevScu
221
+ ? prevScu . call ( this , p , s , c )
222
+ : true
223
+ : false ;
224
+ } ;
225
+ }
193
226
}
194
227
195
228
return hookState . _nextValue || hookState . _value ;
@@ -359,6 +392,7 @@ export function useErrorBoundary(cb) {
359
392
function flushAfterPaintEffects ( ) {
360
393
let internal ;
361
394
while ( ( internal = afterPaintEffects . shift ( ) ) ) {
395
+ if ( ! internal . data . __hooks ) continue ;
362
396
if ( ~ internal . flags & MODE_UNMOUNTING ) {
363
397
try {
364
398
internal . data . __hooks . _pendingEffects . forEach ( invokeCleanup ) ;
0 commit comments