barcis89
(Bartlomiej Woronin)
1
Hi community!
I would be grateful if someone could point me: why in this case .map doesn't work. I mean: finish function is never called, despite that fact incrementButtonTapped is called, then testAction is called and finally, unfortunatelly finish action is not called :(
struct CounterState: Equatable {
var count = 0
}
enum CounterAction: Equatable {
case decrementButtonTapped
case incrementButtonTapped
case finish(Result<String, Never>)
}
struct CounterEnvironment {
var mainQueue: AnySchedulerOf<DispatchQueue>
static let live = CounterEnvironment(
mainQueue: DispatchQueue.main.eraseToAnyScheduler()
)
func testAction() -> Effect<Void, Never> {
Effect<Void, Never>.fireAndForget {
print("testAction")
}
}
}
let counterReducer = Reducer<CounterState, CounterAction, CounterEnvironment> { state, action, environment in
switch action {
case .decrementButtonTapped:
state.count -= 1
return .none
case .incrementButtonTapped:
state.count += 1
return environment.testAction()
.receive(on: environment.mainQueue)
.catchToEffect()
.map { reslt -> CounterAction in
return CounterAction.finish(.success("success"))
}
case let .finish(.success(response)):
print("finish")
return .none
case .finish(.failure):
print("failure")
return .none
}
}
.signpost()
struct CounterView: View {
let store: Store<CounterState, CounterAction>
var body: some View {
WithViewStore(self.store) { viewStore in
HStack {
Button("−") { viewStore.send(.decrementButtonTapped) }
Text("\(viewStore.count)")
.font(Font.body.monospacedDigit())
Button("+") { viewStore.send(.incrementButtonTapped) }
}
}
}
}
mbrandonw
(Brandon Williams)
2
This is happening because the testAction() effect never emits anything, and so .map is never invoked with any data. This would be the equivalent of the following in vanilla Combine code:
Empty<Int, Never>()
.map { $0 /* never called */ }
I'm guessing that testAction() should be actually emitting some values, which would then be fed into your .map.
barcis89
(Bartlomiej Woronin)
3
Thank you @mbrandonw for your response!!
if you could also answer: how is the best way to just call finish effect when testAction is finished.
Here my intention is to do some calculations in testAction and in the body of this function I don't wanna emit anything. But after when it finishes I wanna call next effect, which is called finish.
Thank you so much for your help!!!!!
mbrandonw
(Brandon Williams)
4
Since the effect is a Void effect you can just emit () when the computation is done to signify that it finished. You can even use the .future effect to do this:
Effect<Void, Never>.future { callback in
// do long computation...
// Invoke callback to signal that the computation is done
callback(.success(()))
}
.map { /* do something when computation is finished */ }
1 Like
barcis89
(Bartlomiej Woronin)
5
@mbrandonw you are a real magician!!! Thank you so much for your help!!!!