Skip to content

Instantly share code, notes, and snippets.

@achernoprudov
Last active November 24, 2020 05:06
Show Gist options
  • Save achernoprudov/bbd005c4bbd6833eb2281b1aa8a94cc8 to your computer and use it in GitHub Desktop.
Save achernoprudov/bbd005c4bbd6833eb2281b1aa8a94cc8 to your computer and use it in GitHub Desktop.
Redux implementation with Combine framework
/// This is peruly marker protocol,
/// it allows us to keep action list open, and add more actions
/// without breaking existed components.
///
/// Also sometimes it is nice to implement `Codable` or `Equatable`
public protocol Action {}
import Combine
/// Common Redux reducer contract
public typealias Reducer<State, Action, Environment> =
(inout State, Action, Environment) -> AnyPublisher<Action, Never>?
import Combine
/// Redux store.
///
/// For information: https://swiftwithmajid.com/2019/09/18/redux-like-state-container-in-swiftui
///
/// `State` - module state.
/// `Action` - redux action for communication/modification state
/// `Environment` - abstraction for providing dependencies to reducer
public final class Store<State, Action, Environment>: ObservableObject {
@Published
public private(set) var state: State
private let environment: Environment
private let reducer: Reducer<State, Action, Environment>
private let queue = DispatchQueue(label: "com.skybonds.redux.store", qos: .userInitiated)
private var cancellables: Set<AnyCancellable> = []
public init(
initialState: State,
reducer: @escaping Reducer<State, Action, Environment>,
environment: Environment
) {
self.state = initialState
self.reducer = reducer
self.environment = environment
}
public func send(_ action: Action) {
queue.async {
guard let effect = self.reducer(&self.state, action, self.environment) else {
return
}
let cancellable = effect
.sink(receiveValue: self.send)
self.cancellables.insert(cancellable)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment