From 18ebadf13b1e610f34ce4d7efad72321e68538cb Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 1 Mar 2018 21:18:19 -0500 Subject: [PATCH] Data: Avoid calling listeners on unchanging state --- data/index.js | 14 +++++++++++++- data/test/index.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/data/index.js b/data/index.js index 85b67b7c3b247..765a3d52cd3d2 100644 --- a/data/index.js +++ b/data/index.js @@ -72,7 +72,19 @@ export function registerReducer( reducerKey, reducer ) { } const store = createStore( reducer, flowRight( enhancers ) ); stores[ reducerKey ] = store; - store.subscribe( globalListener ); + + // Customize subscribe behavior to call listeners only on effective change, + // not on every dispatch. + let lastState = store.getState(); + store.subscribe( () => { + const state = store.getState(); + const hasChanged = state !== lastState; + lastState = state; + + if ( hasChanged ) { + globalListener(); + } + } ); return store; } diff --git a/data/test/index.js b/data/test/index.js index 12cfd573adbbf..e638e2ba1ccf7 100644 --- a/data/test/index.js +++ b/data/test/index.js @@ -253,6 +253,26 @@ describe( 'withSelect', () => { store.dispatch( { type: 'increment' } ); } ); + + itWithExtraAssertions( 'should not rerun selection on unchanging state', () => { + const store = registerReducer( 'unchanging', ( state = {} ) => state ); + + registerSelectors( 'unchanging', { + getState: ( state ) => state, + } ); + + const mapSelectToProps = jest.fn(); + + const Component = compose( [ + withSelectImplementation( mapSelectToProps ), + ] )( () =>
); + + wrapper = mount( ); + + store.dispatch( { type: 'dummy' } ); + + expect( mapSelectToProps ).toHaveBeenCalledTimes( 1 ); + } ); } cases( withSelect ); @@ -380,6 +400,16 @@ describe( 'subscribe', () => { expect( secondListener ).toHaveBeenCalled(); } ); + + it( 'does not call listeners if state has not changed', () => { + const store = registerReducer( 'unchanging', ( state = {} ) => state ); + const listener = jest.fn(); + subscribeWithUnsubscribe( listener ); + + store.dispatch( { type: 'dummy' } ); + + expect( listener ).not.toHaveBeenCalled(); + } ); } ); describe( 'dispatch', () => {