@@ -30,6 +30,7 @@ import {
30
30
} from 'react-redux'
31
31
import type { Action , AnyAction , Store } from 'redux'
32
32
import { createStore } from 'redux'
33
+ import { configureStore , createSlice } from '@reduxjs/toolkit'
33
34
34
35
// disable checks by default
35
36
function ProviderMock < A extends Action < any > = AnyAction , S = unknown > ( {
@@ -441,6 +442,137 @@ describe('React', () => {
441
442
expect ( selector ) . toHaveBeenCalledTimes ( 2 )
442
443
expect ( renderedItems . length ) . toEqual ( 2 )
443
444
} )
445
+
446
+ it . only ( 'only calls selectors if the state they depend on has changed' , ( ) => {
447
+ const sliceA = createSlice ( {
448
+ name : 'a' ,
449
+ initialState : 0 ,
450
+ reducers : {
451
+ incrementA : ( state ) => state + 1 ,
452
+ } ,
453
+ } )
454
+
455
+ const sliceB = createSlice ( {
456
+ name : 'b' ,
457
+ initialState : 0 ,
458
+ reducers : {
459
+ incrementB : ( state ) => state + 1 ,
460
+ } ,
461
+
462
+ extraReducers : ( builder ) => {
463
+ builder . addCase ( 'incrementBC' , ( state ) => state + 1 )
464
+ } ,
465
+ } )
466
+
467
+ const sliceC = createSlice ( {
468
+ name : 'c' ,
469
+ initialState : 0 ,
470
+ reducers : {
471
+ incrementC : ( state ) => state + 1 ,
472
+ } ,
473
+ extraReducers : ( builder ) => {
474
+ builder . addCase ( 'incrementBC' , ( state ) => state + 1 )
475
+ } ,
476
+ } )
477
+
478
+ const store = configureStore ( {
479
+ reducer : {
480
+ a : sliceA . reducer ,
481
+ b : sliceB . reducer ,
482
+ c : sliceC . reducer ,
483
+ } ,
484
+ } )
485
+
486
+ type RootState = ReturnType < typeof store . getState >
487
+
488
+ type StateKeys = 'a' | 'b' | 'c'
489
+
490
+ const { incrementA } = sliceA . actions
491
+ const { incrementB } = sliceB . actions
492
+ const { incrementC } = sliceC . actions
493
+
494
+ let selectorACalls = 0
495
+ let selectorBCalls = 0
496
+ let selectorCCalls = 0
497
+ let selectorABCalls = 0
498
+
499
+ const selectA = ( state : RootState ) => ( selectorACalls ++ , state . a )
500
+ const selectB = ( state : RootState ) => ( selectorBCalls ++ , state . b )
501
+ const selectC = ( state : RootState ) => ( selectorCCalls ++ , state . c )
502
+ const selectAB = ( state : RootState ) => {
503
+ selectorABCalls ++
504
+ return state . a + state . b
505
+ }
506
+
507
+ function SliceA ( ) {
508
+ const a = useSelector ( selectA )
509
+ return null
510
+ }
511
+
512
+ function SliceB ( ) {
513
+ const b = useSelector ( selectB )
514
+ return null
515
+ }
516
+
517
+ function SliceC ( ) {
518
+ const c = useSelector ( selectC )
519
+ return null
520
+ }
521
+
522
+ function AB ( ) {
523
+ const ab = useSelector ( selectAB )
524
+ return null
525
+ }
526
+
527
+ rtl . render (
528
+ < ProviderMock store = { store } >
529
+ < SliceA />
530
+ < SliceB />
531
+ < SliceC />
532
+ < AB />
533
+ </ ProviderMock > ,
534
+ )
535
+ expect ( selectorACalls ) . toBe ( 1 )
536
+ expect ( selectorBCalls ) . toBe ( 1 )
537
+ expect ( selectorCCalls ) . toBe ( 1 )
538
+ expect ( selectorABCalls ) . toBe ( 1 )
539
+
540
+ rtl . act ( ( ) => {
541
+ store . dispatch ( incrementA ( ) )
542
+ } )
543
+
544
+ expect ( selectorACalls ) . toBe ( 2 )
545
+ expect ( selectorBCalls ) . toBe ( 1 )
546
+ expect ( selectorCCalls ) . toBe ( 1 )
547
+ expect ( selectorABCalls ) . toBe ( 2 )
548
+
549
+ rtl . act ( ( ) => {
550
+ store . dispatch ( incrementB ( ) )
551
+ } )
552
+
553
+ expect ( selectorACalls ) . toBe ( 2 )
554
+ expect ( selectorBCalls ) . toBe ( 2 )
555
+ expect ( selectorCCalls ) . toBe ( 1 )
556
+ expect ( selectorABCalls ) . toBe ( 3 )
557
+
558
+ rtl . act ( ( ) => {
559
+ store . dispatch ( incrementC ( ) )
560
+ } )
561
+
562
+ expect ( selectorACalls ) . toBe ( 2 )
563
+ expect ( selectorBCalls ) . toBe ( 2 )
564
+ expect ( selectorCCalls ) . toBe ( 2 )
565
+ expect ( selectorABCalls ) . toBe ( 3 )
566
+
567
+ rtl . act ( ( ) => {
568
+ store . dispatch ( { type : 'incrementBC' } )
569
+ } )
570
+
571
+ expect ( selectorACalls ) . toBe ( 2 )
572
+ expect ( selectorBCalls ) . toBe ( 3 )
573
+ expect ( selectorCCalls ) . toBe ( 3 )
574
+ expect ( selectorABCalls ) . toBe ( 4 )
575
+ } )
444
576
} )
445
577
446
578
it ( 'uses the latest selector' , ( ) => {
0 commit comments