Stateless pullback for reducers

I'm wanting to generate temporal views that are not bound to any external state. I do however, want the final result of this view to be available. My use case would be something like this

enum ListAction {
  case add(Thing)
}


struct AddEditState { 
  var scratchThing: Thing? 
}

// In reducer
case .submitTapped:
  guard let t = scratchThing else { return .none }

  /// Here I want to send "t" up to ListAction.add.  But I can't seem to 
  /// make that connection

I don't want the ListViewState to have to have an AddEditState on it. But I want listViewReducer to be able to get the result of the AddEditState and perform necessary actions.

I've created an extension on ViewStore to solve my problem. But wondering if this is the wrong way to go about it.

extension ViewStore {
    public func glue<LocalState, LocalAction, LocalEnvironment>(
        initialState: LocalState,
        reducer: Reducer<LocalState, LocalAction, LocalEnvironment>,
        environment: LocalEnvironment,
        with actionMap: @escaping (LocalAction) -> Action? = { _ in nil }
    ) -> Store<LocalState, LocalAction> {
        
        Store<LocalState, LocalAction>(
            initialState: initialState,
            reducer: Reducer { state, action, env in
                
                /// Here we want to add an optional mapping action to the parent store
                if let globalAction = actionMap(action) {
                    self.send(globalAction)
                }
                
                return reducer(&state, action, env)
            }.debug(),
            environment: environment
        )
    }
}

Which gets used like this

/// The goal here is to create a statelss binding to the  reducer action.
/// We're basically creating a new store for the `ViewOnlyCoreView`
/// and we're adding an action mapper to allow us to say which `ViewOnlyCore.Actions`
/// should get sent up the chain, and how
ViewOnlyCoreView(
    store: viewStore.glue(
        initialState: ViewOnlyCore.State(),
        reducer: ViewOnlyCore.reducer,
        environment: ViewOnlyCore.Environment(),
        with: { localAction in
            
            // We ONLY care about the item submitted here
            guard case .itemSubmitted(let item) = localAction else {
                return nil
            }
            
            // Tells our glue that the .itemSubmittedAction should
            // Map to our DataOnlyAction.addItem
            return ListViewAction.addItem(item)
        }
    )
)

Questions:

  • Is this the wrong way to go about it?
  • Is there something I'm missing that's already capable of handling this case?
  • Does my code look good? (kidding)
Terms of Service

Privacy Policy

Cookie Policy