From 16c092dae0c9c84bb540a7078bd7b20682ae2a62 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Thu, 24 Jun 2021 15:13:03 -0400 Subject: [PATCH] Coalesce synchronous effectful mutations to state --- Sources/ComposableArchitecture/Store.swift | 35 +++++++------------ .../StoreTests.swift | 2 +- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/Sources/ComposableArchitecture/Store.swift b/Sources/ComposableArchitecture/Store.swift index 122e74588424..e892e9b5452f 100644 --- a/Sources/ComposableArchitecture/Store.swift +++ b/Sources/ComposableArchitecture/Store.swift @@ -119,7 +119,6 @@ public final class Store { private var isSending = false private var parentCancellable: AnyCancellable? private let reducer: (inout State, Action) -> Effect - private var synchronousActionsToSend: [Action] = [] private var bufferedActions: [Action] = [] /// Initializes a store from an initial state, a reducer, and an environment. @@ -360,41 +359,31 @@ public final class Store { } func send(_ action: Action) { - if !self.isSending { - self.synchronousActionsToSend.append(action) - } else { - self.bufferedActions.append(action) - return - } - - while !self.synchronousActionsToSend.isEmpty || !self.bufferedActions.isEmpty { - let action = - !self.synchronousActionsToSend.isEmpty - ? self.synchronousActionsToSend.removeFirst() - : self.bufferedActions.removeFirst() + self.bufferedActions.append(action) + guard !self.isSending else { return } - self.isSending = true - let effect = self.reducer(&self.state.value, action) + self.isSending = true + var currentState = self.state.value + defer { + self.state.value = currentState self.isSending = false + } + + while !self.bufferedActions.isEmpty { + let action = self.bufferedActions.removeFirst() + let effect = self.reducer(¤tState, action) var didComplete = false let uuid = UUID() - - var isProcessingEffects = true let effectCancellable = effect.sink( receiveCompletion: { [weak self] _ in didComplete = true self?.effectCancellables[uuid] = nil }, receiveValue: { [weak self] action in - if isProcessingEffects { - self?.synchronousActionsToSend.append(action) - } else { - self?.send(action) - } + self?.send(action) } ) - isProcessingEffects = false if !didComplete { self.effectCancellables[uuid] = effectCancellable diff --git a/Tests/ComposableArchitectureTests/StoreTests.swift b/Tests/ComposableArchitectureTests/StoreTests.swift index ae0e4eda42c0..f895cbd06701 100644 --- a/Tests/ComposableArchitectureTests/StoreTests.swift +++ b/Tests/ComposableArchitectureTests/StoreTests.swift @@ -434,6 +434,6 @@ final class StoreTests: XCTestCase { viewStore.send(0) - XCTAssertEqual(emissions, [0, 1, 2, 3]) + XCTAssertEqual(emissions, [0, 3]) } }