Would implementing `receive(on:)` on Effect be desireable?

In my work I've found that if I'm working with external dependencies that return effects, that I need to receive values on the main queue before making UI updates. However if I do that, I often need to re-erase to an effect (for example):

let reducer = MyReducer { state, action, env in
  switch action {
    case .onAppear:
      return env.api
        .loadData()
        .map(.dataLoaded)
        .receive(on: env.mainScheduler)
        .eraseToEffect()
    case .dataLoaded(let data):
      state.data = data
      return .none
}

In this case, if loadData returned an Effect, it wouldn't matter since there's no receive(on:) overload on Effect, which means the return value is just a publisher that needs to be erased again. If Effect had a custom receive(on:) overload that specified an Effect as a return value, I could take advantage of dependencies that return effects and make my reducer code a little bit less verbose by omitting eraseToEffect calls in more places.

Is this something that would be useful or wanted in TCA itself?

1 Like

So the motivation is essentially just to remove the need to eraseToEffect at the end? I don't think that would pass the bar to be included in the core framework — it isn't necessary for composition. That's just my opinion, though.

Definitely an interesting idea! We already overload map, so overloading receive(on:) could be worth it, given how often it's done. Let's start thinking about it.

2 Likes

Alternatively, could you pass your scheduler in to loadData() such that the returned Effect is on main?

Passing a scheduler into loadData is possible, but that seems like it'd just be reinventing receive(on:) in a less-extensible or reusable way. I'd still have to erase to effect inside the implementation of the loadData method, and i guess from a more ideological viewpoint, it seems superfluous, since you may not want to force the api consumer to choose a scheduler to run things on when you call loadData, since it's pretty well known you can call receive(on:) at any point in a combine operator chain.