diff --git a/.gitignore b/.gitignore index 4c3f3d9..b48f798 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ *.perspectivev3 !default.perspectivev3 xcuserdata -profile *.moved-aside DerivedData .idea/ @@ -19,3 +18,4 @@ Carthage/Checkouts/* Carthage/Build/* /fastlane/report.xml /.ruby-version +*.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/RedUx/Source/Store.swift b/RedUx/Source/Store.swift index 7162af0..ab816cb 100644 --- a/RedUx/Source/Store.swift +++ b/RedUx/Source/Store.swift @@ -28,6 +28,9 @@ public final class Store { private let middlewares: [AnyMiddleware] private var middlewareTasks: [Task] = [] + private var eventBacklog: [Event] = [] + private var isProcessingEvent = false + // MARK: Initialization /// Construct a Store with state, reducer and environment. @@ -70,16 +73,30 @@ public final class Store { /// Send an event through the store's reducer. /// - Parameter event: The event. public func send(_ event: Event) { - let eventStream = self.reducer(&self.state, event, self.environment) + self.eventBacklog.append(event) + guard !self.isProcessingEvent else { return } - Task { - for middleware in self.middlewares { - await middleware.execute(event: event, state: { self.state }) - } + self.isProcessingEvent = true + var state = self.state + + defer { + self.isProcessingEvent = false + self.state = state + } + + while !self.eventBacklog.isEmpty { + let event = self.eventBacklog.removeFirst() + let eventStream = self.reducer(&state, event, self.environment) - guard let eventStream = eventStream else { return } - for await event in eventStream { - self.send(event) + Task { [state] in + for middleware in self.middlewares { + await middleware.execute(event: event, state: { state }) + } + + guard let eventStream = eventStream else { return } + for await event in eventStream { + self.send(event) + } } } } @@ -118,8 +135,9 @@ extension Store { ) -> Store { let scopedStore = Store( state: toScopedState(self.state), - reducer: .init { _, event, _ in + reducer: .init { state, event, _ in self.send(fromScopedEvent(event)) + state = toScopedState(self.state) return .none }, environment: toScopedEnvironment(self.environment),