Skip to content

Commit

Permalink
Data: Fix issue with in-stack unsubscribe
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Feb 26, 2018
1 parent f3c1e22 commit dde60a8
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
8 changes: 7 additions & 1 deletion data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ let listeners = [];
* Global listener called for each store's update.
*/
export function globalListener() {
listeners.forEach( listener => listener() );
// Use for loop instead of Array#forEach, as it's possible a listener's
// behavior causes one further in the stack to be unsubscribed. The
// latter's callback should not be called, which requires monitoring
// changes to the array as they occur in iteration.
for ( let i = 0; i < listeners.length; i++ ) {
listeners[ i ]();
}
}

/**
Expand Down
29 changes: 29 additions & 0 deletions data/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,20 @@ describe( 'withDispatch', () => {
} );

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

function subscribeWithUnsubscribe( ...args ) {
const unsubscribe = subscribe( ...args );
unsubscribes.push( unsubscribe );
return unsubscribe;
}

it( 'registers multiple selectors to the public API', () => {
let incrementedValue = null;
const store = registerReducer( 'myAwesomeReducer', ( state = 0 ) => state + 1 );
Expand All @@ -233,6 +247,21 @@ describe( 'subscribe', () => {

expect( incrementedValue ).toBe( 3 );
} );

it( 'avoids calling a later listener if unsubscribed during earlier callback', () => {
const store = registerReducer( 'myAwesomeReducer', ( state = 0 ) => state + 1 );
const firstListener = jest.fn( () => {
secondUnsubscribe();
} );
const secondListener = jest.fn();

subscribeWithUnsubscribe( firstListener );
const secondUnsubscribe = subscribeWithUnsubscribe( secondListener );

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

expect( secondListener ).not.toHaveBeenCalled();
} );
} );

describe( 'dispatch', () => {
Expand Down

0 comments on commit dde60a8

Please sign in to comment.