Skip to content

Instantly share code, notes, and snippets.

@woodycatliu
Last active February 23, 2022 08:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save woodycatliu/ba0239e30255c08e22f06925142a3ee8 to your computer and use it in GitHub Desktop.
Save woodycatliu/ba0239e30255c08e22f06925142a3ee8 to your computer and use it in GitHub Desktop.
Refactor to make it a more complete and llke TCA

Redux and TCA Learning Record 2


Pervious ParseTCA, I created some encapsulation to reproduce how TCA to implement in binding to ViewStore and Store.

Today, I will try to refactor them to more complete, like composable action and flexibility.

Step 1.

Refocator Reducer

// refactor after: 
typealias Reducer<State, Action> = (inout State, Action)-> AnyPublisher<Action, Never>?

Step 2.

Refactor Store

/// refactor after:
func send(action: Action) {
        guard let effect = void(&publisher.value, action) else { return }
        effect
            .sink(receiveValue: send)
            .store(in: &bag)
    }
import Foundation
import Combine
// before: Reducer<State, Action> = (inout State, Action)-> Void
typealias Reducer<State, Action> = (inout State, Action)-> AnyPublisher<Action, Never>?
class Store<State, Action> {
var publisher: CurrentValueSubject<State, Never>
private var void: Reducer<State, Action>
private var bag: Set<AnyCancellable> = []
init(state: State, reducer: @escaping Reducer<State, Action>) {
publisher = CurrentValueSubject(state)
self.void = reducer
}
deinit {
print("\(Self.self) is deinit")
}
// berfore:
// func send(action: Action) {
// void(&publisher.value, action)
// }
func send(action: Action) {
guard let effect = void(&publisher.value, action) else { return }
effect
.sink(receiveValue: send)
.store(in: &bag)
}
func viewStore()-> ViewStore<State, Action> {
let child = ViewStore(value: publisher.value, root: {
[weak self] action in
self?.send(action: action)
})
child.cancelable = publisher
.dropFirst()
.sink(receiveValue: { [weak child] in
child?.value = $0
})
return child
}
}
class ViewStore<State, Action> {
var cancelable: AnyCancellable?
var publisher: CurrentValueSubject<State, Never>
private var root: ((Action)-> Void)?
init(value: State, root: @escaping (Action)-> Void) {
self.publisher = CurrentValueSubject(value)
self.root = root
}
func send(action: Action) {
root?(action)
}
deinit {
print("\(Self.self) is deinit")
}
}
extension ViewStore {
var value: State {
get {
self.publisher.value
}
set {
self.publisher.send(newValue)
}
}
}
import Combine
var bag: Set<AnyCancellable> = []
var parent: Store! = Store(state: CounterState(), reducer: reducer)
var child: ViewStore! = parent.viewStore()
child.publisher.print().sink(receiveValue: {_ in }).store(in: &bag)
child.send(action: .decrement) // -1
child.send(action: .increment) // 0
child.send(action: .decrement) // -1
child.send(action: .decrement) // -2
child.send(action: .decrement) // -3
child.send(action: .multiplier(5)) // - 15
print(parent.publisher.value.count == -15)
print(child.value.count == -15)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment