Map dosen't work

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) }
      }
    }
  }
}

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.

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!!!!!

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

@mbrandonw you are a real magician!!! Thank you so much for your help!!!!

Terms of Service

Privacy Policy

Cookie Policy