Skip to content

Commit

Permalink
Data: Avoid calling listeners on unchanging state
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Mar 2, 2018
1 parent 3134e1a commit 4521b50
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 12 deletions.
14 changes: 13 additions & 1 deletion data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
51 changes: 40 additions & 11 deletions data/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,19 @@ describe( 'select', () => {
} );

describe( 'withSelect', () => {
let wrapper;

const unsubscribes = [];
afterEach( () => {
let unsubscribe;
while ( ( unsubscribe = unsubscribes.shift() ) ) {
unsubscribe();
}

if ( wrapper ) {
wrapper.unmount();
wrapper = null;
}
} );

function subscribeWithUnsubscribe( ...args ) {
Expand All @@ -131,7 +138,7 @@ describe( 'withSelect', () => {
data: _select( 'reactReducer' ).reactSelector( ownProps.keyName ),
} ) )( ( props ) => <div>{ props.data }</div> );

const wrapper = mount( <Component keyName="reactKey" /> );
wrapper = mount( <Component keyName="reactKey" /> );

// Wrapper is the enhanced component. Find props on the rendered child.
const child = wrapper.childAt( 0 );
Expand All @@ -140,8 +147,6 @@ describe( 'withSelect', () => {
data: 'reactState',
} );
expect( wrapper.text() ).toBe( 'reactState' );

wrapper.unmount();
} );

it( 'should rerun selection on state changes', () => {
Expand Down Expand Up @@ -174,15 +179,33 @@ describe( 'withSelect', () => {
</button>
) );

const wrapper = mount( <Component /> );
wrapper = mount( <Component /> );

const button = wrapper.find( 'button' );

button.simulate( 'click' );

expect( button.text() ).toBe( '1' );
} );

it( '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( [
withSelect( mapSelectToProps ),
] )( () => <div /> );

wrapper = mount( <Component /> );

store.dispatch( { type: 'dummy' } );

wrapper.unmount();
expect( mapSelectToProps ).toHaveBeenCalledTimes( 1 );
} );

it( 'should rerun selection on props changes', () => {
Expand All @@ -202,13 +225,11 @@ describe( 'withSelect', () => {
count: _select( 'counter' ).getCount( ownProps.offset ),
} ) )( ( props ) => <div>{ props.count }</div> );

const wrapper = mount( <Component offset={ 0 } /> );
wrapper = mount( <Component offset={ 0 } /> );

wrapper.setProps( { offset: 10 } );

expect( wrapper.childAt( 0 ).text() ).toBe( '10' );

wrapper.unmount();
} );

it( 'ensures component is still mounted before setting state', () => {
Expand Down Expand Up @@ -236,7 +257,7 @@ describe( 'withSelect', () => {
count: _select( 'counter' ).getCount( ownProps.offset ),
} ) )( ( props ) => <div>{ props.count }</div> );

const wrapper = mount( <Component offset={ 0 } /> );
wrapper = mount( <Component offset={ 0 } /> );

store.dispatch( { type: 'increment' } );
} );
Expand Down Expand Up @@ -281,8 +302,6 @@ describe( 'withDispatch', () => {
wrapper.find( 'button' ).simulate( 'click' );

expect( store.getState() ).toBe( 2 );

wrapper.unmount();
} );
} );

Expand Down Expand Up @@ -354,6 +373,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', () => {
Expand Down

0 comments on commit 4521b50

Please sign in to comment.