This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Sergey Leschev
We already implemented a unidirectional flow that accepts user actions and modifies the state, but what about async actions
which we usually call side effects. How to bake a support for async tasks into our store type? I think it is a good time to introduce the usage of Combine framework that perfectly fits async task processing.
typealias Reducer<State, Action, Environment> =
(inout State, Action, Environment) -> AnyPublisher<Action, Never>?
We add support for async tasks
by changing Reducer
typealias, it has the additional parameter called Environment
. Environment
might be a plain struct that holds all needed dependencies like service and manager classes.
func appReducer(
state: inout AppState,
action: AppAction,
environment: Environment
) -> AnyPublisher<AppAction, Never>? {
switch action {
case let .setSearchResults(repos):
state.searchResult = repos
case let .search(query):
return environment.service
.searchPublisher(matching: query)
.replaceError(with: [])
.map { AppAction.setSearchResults(repos: $0) }
.eraseToAnyPublisher()
}
return nil
}
Side Effect is a sequence of Actions
which we can publish using Combine
framework’s Publisher
type. It allows us to handle async job and then publish an action that will be used by reducer
to change the current state.
final class Store<State, Action, Environment>: ObservableObject {
@Published private(set) var state: State
private let environment: Environment
private let reducer: Reducer<State, Action, Environment>
private var cancellables: Set<AnyCancellable> = []
init(
initialState: State,
reducer: @escaping Reducer<State, Action, Environment>,
environment: Environment
) {
self.state = initialState
self.reducer = reducer
self.environment = environment
}
func send(_ action: Action) {
guard let effect = reducer(&state, action, environment) else {
return
}
effect
.receive(on: DispatchQueue.main)
.sink(receiveValue: send)
.store(in: &cancellables)
}
}
We build a Store
type that supports async tasks. Usually, reducer resolves an action by applying it on top of the state. In case of an async action, reducer returns it as Combine Publisher
, then Store run it and send result back to the reducer as a plain action.
Contacts
I have a clear focus on time-to-market and don't prioritize technical debt. And I took part in the Pre-Sale/RFX activity as a System Architect, assessment efforts for Mobile (iOS-Swift, Android-Kotlin), Frontend (React-TypeScript) and Backend (NodeJS-.NET-PHP-Kafka-SQL-NoSQL). And I also formed the work of Pre-Sale as a CTO from Opportunity to Proposal via knowledge transfer to Successful Delivery.
🛩️ #startups #management #cto #swift #typescript #database
📧 Email: sergey.leschev@gmail.com
đź‘‹ LinkedIn: https://www.linkedin.com/in/sergeyleschev/
đź‘‹ LeetCode: https://leetcode.com/sergeyleschev/
đź‘‹ Twitter: https://twitter.com/sergeyleschev
đź‘‹ Github: https://github.com/sergeyleschev
🌎 Website: https://sergeyleschev.github.io
This content originally appeared on DEV Community 👩‍💻👨‍💻 and was authored by Sergey Leschev
Sergey Leschev | Sciencx (2023-02-11T15:55:41+00:00) Redux-like state container in SwiftUI. Side effects.. Retrieved from https://www.scien.cx/2023/02/11/redux-like-state-container-in-swiftui-side-effects/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.