Skip to content

Instantly share code, notes, and snippets.

@woodycatliu
Last active February 23, 2022 08:02
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/0ae4b5cf5b7ad7d8dffc26013c78d2f9 to your computer and use it in GitHub Desktop.
Save woodycatliu/0ae4b5cf5b7ad7d8dffc26013c78d2f9 to your computer and use it in GitHub Desktop.
How does implement of Store and ViewStore in TCA

Redux and TCA Learning Record 1


We can use Store and compose a new ViewStore to binding a smaller UI Block in subView or subViewController. How does TCA implements in binding each other ?

I crate some code to reproduce it.

Implement

Test

import Foundation
import Combine
class Store<State, Action> {
var publisher: CurrentValueSubject<State, Never>
var void: Reducer<State, Action>
var cancelable: AnyCancellable?
init(state: State, reducer: @escaping Reducer<State, Action>) {
publisher = CurrentValueSubject(state)
self.void = reducer
}
deinit {
print("\(Self.self) is deinit")
}
func send(action: Action) {
void(&publisher.value, action)
}
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>
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 Foundation
import Combine
enum CounterAction {
case decrement
case increment
}
struct CounterState {
var count: Int = 0
}
typealias Reducer<State, Action> = (inout State, Action)-> Void
let reducer: Reducer<CounterState, CounterAction> = { state , action in
switch action {
case .decrement:
state.count -= 1
case .increment:
state.count += 1
}
}
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
print(parent.publisher.value.count == -3)
print(child.value.count == -3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment