From e13af1d9ad88872b942f410b6deb4cb3e590288d Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Sun, 18 Feb 2024 16:11:43 +0200 Subject: [PATCH 1/9] notify before defer --- src/throttledStore.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/throttledStore.tsx b/src/throttledStore.tsx index d9cf7ee..ab24b40 100644 --- a/src/throttledStore.tsx +++ b/src/throttledStore.tsx @@ -275,6 +275,7 @@ export const createThrottledStore = ( return action() } try { + notifyAll() deferNotifications = true const functionResult = await action() return functionResult From 80c051ee44b2177ed11755e074d1fbc7c4ccb903 Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Mon, 19 Feb 2024 12:54:34 +0200 Subject: [PATCH 2/9] add test --- test/connectWithShell.spec.tsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/connectWithShell.spec.tsx b/test/connectWithShell.spec.tsx index 9e12714..4ae85f5 100644 --- a/test/connectWithShell.spec.tsx +++ b/test/connectWithShell.spec.tsx @@ -668,6 +668,26 @@ describe('connectWithShell-useCases', () => { expect(renderSpy).toHaveBeenCalledTimes(2) }) + it('should not have pending subscribers when starting to defer notifications', async () => { + const { host, shell, renderInShellContext } = createMocks(entryPointWithState, [entryPointSecondStateWithAPI]) + const ConnectedComp = connectWithShell(mapStateToProps, undefined, shell, { allowOutOfEntryPoint: true })(PureComp) + + const { testKit } = renderInShellContext() + if (!testKit) { + throw new Error('Connected component failed to render') + } + + let hasPendingSubscribersWhileDeferring + await act(async () => { + host.getStore().dispatch({ type: 'SET_FIRST_STATE', value: 'update1' }) + await host.getStore().deferSubscriberNotifications(() => { + hasPendingSubscribersWhileDeferring = shell.getStore().hasPendingSubscribers() + }) + }) + + expect(hasPendingSubscribersWhileDeferring).toBe(false) + }) + it('should notify after action failed while deferring notifications', async () => { const { host, shell, renderInShellContext } = createMocks(entryPointWithState, [entryPointSecondStateWithAPI]) const ConnectedComp = connectWithShell(mapStateToProps, undefined, shell, { allowOutOfEntryPoint: true })(PureComp) From 4f276a3c4d93288b392adcb8141041aaa385f574 Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Mon, 19 Feb 2024 13:07:57 +0200 Subject: [PATCH 3/9] only notify if needed --- src/throttledStore.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/throttledStore.tsx b/src/throttledStore.tsx index ab24b40..4d0d6ca 100644 --- a/src/throttledStore.tsx +++ b/src/throttledStore.tsx @@ -275,7 +275,9 @@ export const createThrottledStore = ( return action() } try { - notifyAll() + if (pendingBroadcastNotification || !pendingObservableNotifications) { + notifyAll() + } deferNotifications = true const functionResult = await action() return functionResult From e2d30402e570cae70d601be823c52f7de8956f91 Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Wed, 28 Feb 2024 09:14:28 +0200 Subject: [PATCH 4/9] cleanup --- src/throttledStore.tsx | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/throttledStore.tsx b/src/throttledStore.tsx index 4d0d6ca..bf3de83 100644 --- a/src/throttledStore.tsx +++ b/src/throttledStore.tsx @@ -259,6 +259,16 @@ export const createThrottledStore = ( __shellName: shell.name }) + const excecutePendingActions = () => { + if (pendingFlush) { + pendingFlush = false + flush() + } + if (pendingBroadcastNotification || !pendingObservableNotifications) { + notifyAll() + } + } + const result: PrivateThrottledStore = { ...store, subscribe, @@ -275,20 +285,13 @@ export const createThrottledStore = ( return action() } try { - if (pendingBroadcastNotification || !pendingObservableNotifications) { - notifyAll() - } + excecutePendingActions() deferNotifications = true const functionResult = await action() return functionResult } finally { deferNotifications = false - if (pendingFlush) { - pendingFlush = false - flush() - } else { - notifyAll() - } + excecutePendingActions() } } } From 181c2717f332676d5caae87e1afc1cbb153ed879 Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Wed, 28 Feb 2024 09:16:17 +0200 Subject: [PATCH 5/9] fix typo --- src/throttledStore.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/throttledStore.tsx b/src/throttledStore.tsx index bf3de83..18e747c 100644 --- a/src/throttledStore.tsx +++ b/src/throttledStore.tsx @@ -259,7 +259,7 @@ export const createThrottledStore = ( __shellName: shell.name }) - const excecutePendingActions = () => { + const executePendingActions = () => { if (pendingFlush) { pendingFlush = false flush() @@ -285,13 +285,13 @@ export const createThrottledStore = ( return action() } try { - excecutePendingActions() + executePendingActions() deferNotifications = true const functionResult = await action() return functionResult } finally { deferNotifications = false - excecutePendingActions() + executePendingActions() } } } From ab0d599bc4d94854fbf75056173cc30b8b7355b6 Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Wed, 28 Feb 2024 09:18:37 +0200 Subject: [PATCH 6/9] fix implementation --- src/throttledStore.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/throttledStore.tsx b/src/throttledStore.tsx index 18e747c..465fe81 100644 --- a/src/throttledStore.tsx +++ b/src/throttledStore.tsx @@ -264,8 +264,11 @@ export const createThrottledStore = ( pendingFlush = false flush() } - if (pendingBroadcastNotification || !pendingObservableNotifications) { - notifyAll() + if (pendingBroadcastNotification) { + notifySubscribers() + } + if (pendingObservableNotifications) { + notifyObservers() } } From ac72ebbd12c156bc2d73d9a6fccc3409e9f9b6e4 Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Thu, 29 Feb 2024 09:15:43 +0200 Subject: [PATCH 7/9] use notifyAll --- src/throttledStore.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/throttledStore.tsx b/src/throttledStore.tsx index 465fe81..c4d0823 100644 --- a/src/throttledStore.tsx +++ b/src/throttledStore.tsx @@ -264,11 +264,8 @@ export const createThrottledStore = ( pendingFlush = false flush() } - if (pendingBroadcastNotification) { - notifySubscribers() - } - if (pendingObservableNotifications) { - notifyObservers() + if (pendingBroadcastNotification || pendingObservableNotifications) { + notifyAll() } } From 14a30c7670ea015fdc358494d56448b0a4091763 Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Sun, 3 Mar 2024 11:37:44 +0200 Subject: [PATCH 8/9] rename --- src/throttledStore.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/throttledStore.tsx b/src/throttledStore.tsx index c4d0823..bb57a94 100644 --- a/src/throttledStore.tsx +++ b/src/throttledStore.tsx @@ -161,7 +161,7 @@ export const createThrottledStore = ( ): PrivateThrottledStore => { let pendingBroadcastNotification = false let pendingObservableNotifications: Set | undefined - let deferNotifications = false + let isDeferrringNotifications = false let pendingFlush = false const onBroadcastNotify = () => { @@ -225,7 +225,7 @@ export const createThrottledStore = ( } const scheduledNotifyAll = () => { - if (deferNotifications) { + if (isDeferrringNotifications) { return } notifyAll() @@ -240,7 +240,7 @@ export const createThrottledStore = ( }) const flush = (config = { excecutionType: 'default' }) => { - if (deferNotifications && config.excecutionType !== 'immediate') { + if (isDeferrringNotifications && config.excecutionType !== 'immediate') { pendingFlush = true return } @@ -263,8 +263,7 @@ export const createThrottledStore = ( if (pendingFlush) { pendingFlush = false flush() - } - if (pendingBroadcastNotification || pendingObservableNotifications) { + } else if (pendingBroadcastNotification || pendingObservableNotifications) { notifyAll() } } @@ -281,16 +280,16 @@ export const createThrottledStore = ( resetPendingNotifications: resetAllPendingNotifications, hasPendingSubscribers: () => pendingBroadcastNotification, deferSubscriberNotifications: async action => { - if (deferNotifications) { + if (isDeferrringNotifications) { return action() } try { executePendingActions() - deferNotifications = true + isDeferrringNotifications = true const functionResult = await action() return functionResult } finally { - deferNotifications = false + isDeferrringNotifications = false executePendingActions() } } From 5754f0595b61ce430f3f2dc556a72b095fbb4cce Mon Sep 17 00:00:00 2001 From: ShirShintel Date: Sun, 3 Mar 2024 12:02:34 +0200 Subject: [PATCH 9/9] add test --- test/connectWithShell.spec.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/connectWithShell.spec.tsx b/test/connectWithShell.spec.tsx index 4ae85f5..a390b72 100644 --- a/test/connectWithShell.spec.tsx +++ b/test/connectWithShell.spec.tsx @@ -688,6 +688,24 @@ describe('connectWithShell-useCases', () => { expect(hasPendingSubscribersWhileDeferring).toBe(false) }) + it('should notify subscribers of state changes before deferring notifications', async () => { + const { host, shell, renderInShellContext } = createMocks(entryPointWithState, [entryPointSecondStateWithAPI]) + const ConnectedComp = connectWithShell(mapStateToProps, undefined, shell, { allowOutOfEntryPoint: true })(PureComp) + + const { testKit } = renderInShellContext() + if (!testKit) { + throw new Error('Connected component failed to render') + } + expect(mapStateToPropsSpy).toHaveBeenCalledTimes(1) + + await act(async () => { + host.getStore().dispatch({ type: 'SET_FIRST_STATE', value: 'update1' }) + await host.getStore().deferSubscriberNotifications(() => { + expect(mapStateToPropsSpy).toHaveBeenCalledTimes(2) + }) + }) + }) + it('should notify after action failed while deferring notifications', async () => { const { host, shell, renderInShellContext } = createMocks(entryPointWithState, [entryPointSecondStateWithAPI]) const ConnectedComp = connectWithShell(mapStateToProps, undefined, shell, { allowOutOfEntryPoint: true })(PureComp)