Skip to content

Commit

Permalink
Simplified action dispatcher proxy API
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenLambion committed Feb 8, 2020
1 parent 46d933d commit ed22980
Show file tree
Hide file tree
Showing 11 changed files with 44 additions and 213 deletions.
9 changes: 3 additions & 6 deletions Sources/SwiftDux/Action/ActionDispatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@ public protocol ActionDispatcher {
/// Create a new `ActionDispatcher` that acts as a proxy for the current one.
///
/// Actions can be modified by both the new proxy and the original dispatcher it was created from.
/// - Parameters
/// - modifyAction: An optional closure to modify the action before it continues up stream.
/// - sentAction: Called directly after an action was sent up stream.
/// - Parameter modifyAction: An optional closure to modify the action before it continues up stream.
/// - Returns: a new action dispatcher.
func proxy(modifyAction: ActionModifier?, sentAction: ((Action) -> Void)?) -> ActionDispatcher

func proxy(modifyAction: ActionModifier?) -> ActionDispatcher
}

extension ActionDispatcher {
Expand All @@ -38,7 +35,7 @@ extension ActionDispatcher {
public func callAsFunction(_ action: Action) {
send(action)
}

/// Send an action that returns a cancellable object.
/// - Parameter action: The action
/// - Returns: A cancellable to cancel the action.
Expand Down
29 changes: 0 additions & 29 deletions Sources/SwiftDux/Action/ModifiedAction.swift

This file was deleted.

30 changes: 7 additions & 23 deletions Sources/SwiftDux/Store/Store.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,16 @@ public final class Store<State> where State: StateType {

extension Store: ActionDispatcher {

// swift-format-disable: UseLetInEveryBoundCaseVariable

/// Sends an action to the store to mutate its state.
/// - Parameter action: The action to mutate the state.
public func send(_ action: Action) {
switch action {
case let action as ActionPlan<State>:
if let action = action as? ActionPlan<State> {
send(actionPlan: action)
case let modifiedAction as ModifiedAction:
send(modifiedAction: modifiedAction)
default:
} else {
reduceAction(action)
}
}

// swift-format-enable: UseLetInEveryBoundCaseVariable

/// Handles the sending of normal action plans.
private func send(actionPlan: ActionPlan<State>) {
var cancellable: AnyCancellable? = nil
Expand All @@ -81,23 +74,14 @@ extension Store: ActionDispatcher {
didChangeSubject.send(actionPlan)
}

private func send(modifiedAction: ModifiedAction) {
send(modifiedAction.action)
modifiedAction.previousActions.forEach { self.didChangeSubject.send($0) }
}

/// Create a new `ActionDispatcher` that acts as a proxy between the action sender and the store. It optionally allows actions to be
/// modified or tracked.
/// - Parameters
/// - modifyAction: An optional closure to modify the action before it continues up stream.
/// - sentAction: Called directly after an action was sent up stream.
/// - Parameter modifyAction: An optional closure to modify the action before it continues up stream.
/// - Returns: a new action dispatcher.
public func proxy(modifyAction: ActionModifier? = nil, sentAction: ((Action) -> Void)? = nil) -> ActionDispatcher {
StoreActionDispatcher(
upstream: self,
modifyAction: modifyAction,
sentAction: sentAction
public func proxy(modifyAction: ActionModifier? = nil) -> ActionDispatcher {
StoreProxy<State>(
store: self,
modifyAction: modifyAction
)
}

}
108 changes: 0 additions & 108 deletions Sources/SwiftDux/Store/StoreActionDispatcher.swift

This file was deleted.

24 changes: 21 additions & 3 deletions Sources/SwiftDux/Store/StoreProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public struct StoreProxy<State>: ActionDispatcher where State: StateType {
/// Subscribe to state changes.
private unowned var store: Store<State>

/// Send an action to the next middleware
private var modifyAction: ActionModifier?

/// Send an action to the next middleware
private var nextBlock: SendAction?

Expand All @@ -27,15 +30,30 @@ public struct StoreProxy<State>: ActionDispatcher where State: StateType {
store.didChange
}

internal init(store: Store<State>, next: SendAction? = nil, done: (() -> Void)? = nil) {
internal init(store: Store<State>, modifyAction: ActionModifier? = nil, next: SendAction? = nil, done: (() -> Void)? = nil) {
self.store = store
self.modifyAction = modifyAction
self.nextBlock = next
self.doneBlock = done
}

internal init(store: StoreProxy<State>, modifyAction: ActionModifier? = nil, next: SendAction? = nil, done: (() -> Void)? = nil) {
self.store = store.store
self.modifyAction = modifyAction.flatMap { outer in
store.modifyAction.map { inner in
{ action in
inner(action).flatMap { outer($0) }
}
} ?? outer
}
self.nextBlock = next
self.doneBlock = done
}

/// Send an action to the store.
/// - Parameter action: The action to send
public func send(_ action: Action) {
let action = modifyAction.flatMap { $0(action) } ?? action
store.send(action)
}

Expand All @@ -53,7 +71,7 @@ public struct StoreProxy<State>: ActionDispatcher where State: StateType {
doneBlock?()
}

public func proxy(modifyAction: ActionModifier?, sentAction: ((Action) -> Void)?) -> ActionDispatcher {
fatalError("StoreProxy cannot create an ActionDispatcher proxy.")
public func proxy(modifyAction: ActionModifier?) -> ActionDispatcher {
StoreProxy(store: self, modifyAction: modifyAction)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal struct NoopActionDispatcher: ActionDispatcher {
print("Tried dispatching an action `\(action)` without providing a store object.")
}

func proxy(modifyAction: ActionModifier?, sentAction: ((Action) -> Void)?) -> ActionDispatcher {
func proxy(modifyAction: ActionModifier? = nil) -> ActionDispatcher {
print("Tried proxying an action dispatcher before providing a store object.")
return self
}
Expand Down
7 changes: 5 additions & 2 deletions Sources/SwiftDux/UI/ViewModifiers/OnActionViewModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ internal struct OnActionViewModifier: ViewModifier {
}

public func body(content: Content) -> some View {
let proxy = actionDispatcher.proxy(modifyAction: perform, sentAction: nil)
return content.environment(\.actionDispatcher, proxy)
var nextActionDispatcher = actionDispatcher
if let perform = perform {
nextActionDispatcher = actionDispatcher.proxy(modifyAction: perform)
}
return content.environment(\.actionDispatcher, nextActionDispatcher)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import SwiftUI
internal struct StoreProviderViewModifier<State>: ViewModifier where State: StateType {
private var store: Store<State>
private var connection: StateConnection<State>
private var actionDispatcher: ActionDispatcher

internal init(store: Store<State>) {
self.store = store
Expand All @@ -17,13 +16,12 @@ internal struct StoreProviderViewModifier<State>: ViewModifier where State: Stat
changePublisher: store.didChange,
emitChanges: false
)
self.actionDispatcher = store.proxy()
}

public func body(content: Content) -> some View {
content
.environmentObject(connection)
.environment(\.actionDispatcher, actionDispatcher)
.environment(\.actionDispatcher, store)
.environment(\.storeUpdated, store.didChange)
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftDuxTests/Action/ActionPlanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ final class ActionPlanTests: XCTestCase {
}
}

let cancellable = actionPlan.sendAsCancellable(store)
let cancellable = store.sendAsCancellable(actionPlan)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
cancellable.cancel()
Expand Down
32 changes: 0 additions & 32 deletions Tests/SwiftDuxTests/Action/ModifiedActionTests.swift

This file was deleted.

10 changes: 5 additions & 5 deletions Tests/SwiftDuxTests/StoreActionDispatcherTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ final class StoreActionDispatcherTests: XCTestCase {

func testBasicActionDispatchingValue() {
let store = Store(state: TestState.defaultState, reducer: TestReducer())
let dispatcher = store.proxy()
dispatcher.send(TodoListAction.addTodo(toList: "123", withText: "My Todo"))
let dispatch = store.proxy()
dispatch(TodoListAction.addTodo(toList: "123", withText: "My Todo"))
XCTAssertEqual(store.state.todoLists["123"]?.todos.filter { $0.text == "My Todo"}.count, 1)
}

func testModifyingActionsValue() {
let store = Store(state: TestState.defaultState, reducer: TestReducer())
let dispatcher = store.proxy(modifyAction: {
let dispatch = store.proxy {
if $0 is TodoListAction {
return TestAction.routeTodoAction(forList: "123", action: $0)
}
return $0
})
dispatcher.send(TodoListAction.addTodo2(withText: "My Todo"))
}
dispatch(TodoListAction.addTodo2(withText: "My Todo"))
XCTAssertEqual(store.state.todoLists["123"]?.todos.filter { $0.text == "My Todo"}.count, 1)
}

Expand Down

0 comments on commit ed22980

Please sign in to comment.