From 2ddfd715c8313967db82ef2c957b69b7ff143bb8 Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Tue, 11 Aug 2015 16:14:09 +0200 Subject: [PATCH] Fixes #461 - Copy listeners array, so subscribes can't affect the loop. Unsubscribing during a dispatch would change the listeners array. However that causes the next listener not to fire. --- src/createStore.js | 2 +- test/createStore.spec.js | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/createStore.js b/src/createStore.js index 296bf35caf..e9df7ebcbc 100644 --- a/src/createStore.js +++ b/src/createStore.js @@ -106,7 +106,7 @@ export default function createStore(reducer, initialState) { isDispatching = false; } - listeners.forEach(listener => listener()); + listeners.slice().forEach(listener => listener()); return action; } diff --git a/test/createStore.spec.js b/test/createStore.spec.js index 4e014fbb9e..32aa2ef333 100644 --- a/test/createStore.spec.js +++ b/test/createStore.spec.js @@ -204,6 +204,28 @@ describe('createStore', () => { expect(listenerB.calls.length).toBe(2); }); + it('should support removing a subscription within a subscription', () => { + const store = createStore(reducers.todos); + const listenerA = expect.createSpy(() => {}); + const listenerB = expect.createSpy(() => {}); + const listenerC = expect.createSpy(() => {}); + + store.subscribe(listenerA); + const unSubB = store.subscribe(() => { + listenerB(); + unSubB(); + }); + store.subscribe(listenerC); + + store.dispatch({}); + store.dispatch({}); + + expect(listenerA.calls.length).toBe(2); + expect(listenerB.calls.length).toBe(1); + expect(listenerC.calls.length).toBe(2); + + }); + it('should provide an up-to-date state when a subscriber is notified', done => { const store = createStore(reducers.todos); store.subscribe(() => {