Send an action from one reducer to another

As Brandon's resending implementation uses the now deprecated CasePath.case(case), I thought I'd give it a shot and reimplement it using CasePaths.

extension Reducer {
  func resending<Value>(
    _ extract: @escaping (Action) -> Value?,
    to embed: @escaping (Value) -> Action
  ) -> Self {
    .combine(
      self,
      .init { _, action, _ in
        if let value = extract(action) {
          return Effect(value: embed(value))
        } else {
          return .none
        }
      }
    )
  }

  func resending<Value>(
    _ `case`: CasePath<Action, Value>,
    to other: CasePath<Action, Value>
  ) -> Self {
    resending(`case`.extract(from:), to: other.embed(_:))
  }

  func resending<Value>(
    _ `case`: CasePath<Action, Value>,
    to other: @escaping (Value) -> Action
  ) -> Self {
    resending(`case`.extract(from:), to: other)
  }

  func resending<Value>(
    _ extract: @escaping (Action) -> Value?,
    to other: CasePath<Action, Value>
  ) -> Self {
    resending(extract, to: other.embed(_:))
  }
}

Usage

parentReducer
  .resending(/ParentAction.fooClient, to: /ParentAction.child1 .. Child1Action.fooClient)
  .resending(/ParentAction.fooClient, to: /ParentAction.child2 .. Child2Action.fooClient)
  .resending(/ParentAction.fooClient, to: { value in .boolAction(value > 5) })

If extensions like this one don't have 'a place' in the core lib, should we (as a community) maybe create a space similar to CombineExt and RxSwiftExt that is managed by a TCACommunity?

1 Like