Last active
February 6, 2023 21:29
-
-
Save GreatApe/b2cc42d05471ac50cf85089b583d1551 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import Dependencies | |
import Combine | |
import ComposableArchitecture | |
struct ContentView: View { | |
private let myStore: StoreOf<MyReducer> = Store(initialState: .init(number: 1), reducer: MyReducer()) | |
private let otherStore: StoreOf<OtherReducer> = Store(initialState: .init(number: 2), reducer: OtherReducer()) | |
var body: some View { | |
VStack { | |
MyView(store: myStore) | |
Image(systemName: "globe") | |
.imageScale(.large) | |
.foregroundColor(.accentColor) | |
OtherView(store: otherStore) | |
} | |
.padding() | |
} | |
} | |
struct MyView: View { | |
let store: StoreOf<MyReducer> | |
var body: some View { | |
WithViewStore(store, observe: \.number) { viewStore in | |
Button("MyView: \(viewStore.state)") { | |
viewStore.send(.update) | |
} | |
.onAppear { | |
viewStore.send(.start) | |
} | |
} | |
} | |
} | |
struct OtherView: View { | |
let store: StoreOf<OtherReducer> | |
var body: some View { | |
WithViewStore(store, observe: \.number) { viewStore in | |
Button("OtherView: \(viewStore.state)") { | |
viewStore.send(.update) | |
} | |
.onAppear { | |
viewStore.send(.start) | |
} | |
} | |
} | |
} | |
extension EffectTask where Failure == Never { | |
static func observe<S: AsyncSequence>(_ sequence: S, action: @escaping (S.Element) -> Action) -> Self { | |
run { send in | |
for try await value in sequence { | |
await send(action(value)) | |
} | |
} | |
} | |
} | |
struct MyReducer: ReducerProtocol { | |
@Dependency(\.player) var player | |
struct State { | |
var number: Int | |
} | |
enum Action { | |
case start | |
case update | |
case numberChanged(Int) | |
} | |
func reduce(into state: inout State, action: Action) -> EffectTask<Action> { | |
switch action { | |
case .start: | |
return .observe(player.numbers, action: Action.numberChanged) | |
case .update: | |
player.update() | |
case .numberChanged(let number): | |
state.number = number | |
} | |
return .none | |
} | |
} | |
struct OtherReducer: ReducerProtocol { | |
@Dependency(\.player) var player | |
struct State { | |
var number: Int | |
} | |
enum Action { | |
case start | |
case update | |
case numberChanged(Int) | |
} | |
func reduce(into state: inout State, action: Action) -> EffectTask<Action> { | |
switch action { | |
case .start: | |
return .observe(player.numbers, action: Action.numberChanged) | |
case .update: | |
player.update() | |
case .numberChanged(let number): | |
state.number = number | |
} | |
return .none | |
} | |
} | |
struct PlayerKey: DependencyKey { | |
static var liveValue: Player { .init() } | |
} | |
extension DependencyValues { | |
var player: Player { | |
get { self[PlayerKey.self] } | |
set { self[PlayerKey.self] = newValue } | |
} | |
} | |
struct Player { | |
var numbers: AsyncPublisher<PassthroughSubject<Int, Never>> { numberSubject.values } | |
private let numberSubject = PassthroughSubject<Int, Never>() | |
func update() { | |
let newNumber = Int.random(in: 0...10) | |
numberSubject.send(newNumber) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment