Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Credits to @gsampaio for coming up with the Effect<S, A> type.
- * Even though this flavor of reducer also describes side-effects,
- * testing is still trivial since it's sufficient to check if the
- * side-effects are of the right type. The actual execution of the
- * effect can be tested separately using integration tests. */
- import RxSwift
- class Effect<S: Equatable, A: Action> {
- open func execute(state: () -> S) -> Observable<A> {
- fatalError("not implemented")
- }
- static func empty<S, A>() -> Effect<S, A> {
- return EmptyEffect()
- }
- private class EmptyEffect<S: Equatable, A: Action>: Effect<S, A> {
- override func execute(state: () -> S) -> Observable<A> {
- return .empty()
- }
- }
- }
- protocol Action {}
- struct Reducer<S: Equatable, A: Action> {
- let reduce: (S, A) -> (S, Effect<S, A>)
- init (_ reduce: @escaping (S, A) -> (S, Effect<S, A>)) {
- self.reduce = reduce
- }
- }
- class Store<S: Equatable, A: Action> {
- private let actionSink: AnyObserver<A>
- private let state: Observable<S>
- fileprivate init (actionSink: AnyObserver<A>, state: Observable<S>) {
- self.actionSink = actionSink
- self.state = state
- }
- static func create<S, A>(reducer: Reducer<S, A>, initialState: S) -> Store<S, A> {
- let actionSink: AnyObserver<A>
- let stateSubject = BehaviorSubject<S>(value: initialState)
- var dispatch: (A) -> Void = { _ in }
- var interpret: (Effect<S, A>) -> Void = { _ in }
- var currentState = initialState {
- didSet { stateSubject.onNext(currentState) }
- }
- actionSink = AnyObserver<A> { event in
- switch event {
- case let .next(action): dispatch(action)
- default: break
- }
- }
- dispatch = { action in
- let (nextState, nextEffect) = reducer.reduce(currentState, action)
- currentState = nextState
- interpret(nextEffect)
- }
- interpret = { effect in
- _ = effect.execute(state: { currentState }).subscribe(onNext: dispatch)
- }
- return Store<S, A>(actionSink: actionSink, state: stateSubject)
- }
- func asObserver() -> AnyObserver<A> {
- return actionSink
- }
- func asObservable() -> Observable<S> {
- return state
- }
- }
- //
- class PrintEffect: Effect<PrintState, PrintAction> {
- override func execute(state: () -> PrintState) -> Observable<PrintAction> {
- print("State before effect:", state())
- return .just(.finishPrinting)
- }
- }
- enum PrintAction: Action {
- case startPrinting
- case finishPrinting
- }
- struct PrintState: Equatable {
- let isPrinting: Bool
- static func == (lhs: PrintState, rhs: PrintState) -> Bool {
- return lhs.isPrinting == rhs.isPrinting
- }
- }
- func PrintReducer() -> Reducer<PrintState, PrintAction> {
- return Reducer { _, action in
- switch action {
- case .startPrinting:
- return (PrintState(isPrinting: true), PrintEffect())
- case .finishPrinting:
- return (PrintState(isPrinting: false), .empty())
- }
- }
- }
- let store = Store<PrintState, PrintAction>.create(reducer: PrintReducer(), initialState: PrintState(isPrinting: false))
- _ = store.asObservable().subscribe(onNext: { state in print("Subscribed state:", state) })
- store.asObserver().onNext(.startPrinting)
Add Comment
Please, Sign In to add comment