fmCarlos
(Carlos)
1
Hello guys, I'm struggling to find the way to pullback from a stateless store.
Here's some code to explain the issue
I've a ChildView that has a stateless store
let childReducer = Reducer<Void, ChildAction, ChildEnvironment> { state, action, environment in
switch action {
case .restorePurchasesTapped:
return environment.storeClient.sync()
.fireAndForget()
case .resetTapped:
return .none
case .unlockTapped:
return .none
}
}
On the ParentView I need to pullback the childReducer, but the thing is that the pullback asks me for a WritableKeyPath<GlobalState, Void> but I've no idea how to provide one
let appReducer: Reducer<AppState, AppAction, AppEnvironment> =
.combine(
trainingPlanSettingsReducer.pullback(
state: <#T##WritableKeyPath<GlobalState, Void>#>,
action: /AppAction.trainingPlanAction,
environment: { appEnv in
ChildEnv()
}),
Reducer<TrainingPlanState, TrainingPlanAction, TrainingPlanEnvironment> { state, action, environment in
switch action {
case .startStage(stage: let stage, stageIndex: let index):
return .none
}
}
victor
(Víctor Pimentel)
2
It’s not very pretty, but you could add a Writable Void property (computed or not) to the parent AppState, that way you can reference its keypath.
mayoff
(Rob Mayoff)
3
Since there's only one value (“inhabitant”) of type Void, a pullback for a Reducer where State == Void can just make up a Void value to pass to the wrapped Reducer, and discard the value after the wrapped Reducer returns, without needing a WritableKeyPath. Here's a copy of pullback specialized for State == Void:
extension Reducer {
func pullback<GlobalState, GlobalAction, GlobalEnvironment>(
action toLocalAction: CasePath<GlobalAction, Action>,
environment toLocalEnvironment: @escaping (GlobalEnvironment) -> Environment
) -> Reducer<GlobalState, GlobalAction, GlobalEnvironment>
where State == Void
{
.init { _, globalAction, globalEnvironment in
guard let localAction = toLocalAction.extract(from: globalAction) else { return .none }
var state: Void = ()
return self.reducer(
&state,
localAction,
toLocalEnvironment(globalEnvironment)
)
.map(toLocalAction.embed)
}
}
}
You should be able to use it like this:
let appReducer: Reducer<AppState, AppAction, AppEnvironment> =
.combine(
// Assuming trainingPlanSettingsReducer's State == Void
trainingPlanSettingsReducer.pullback(
// No state keypath needed
action: /AppAction.trainingPlanAction,
environment: { appEnv in
ChildEnv()
}),
Reducer<TrainingPlanState, TrainingPlanAction, TrainingPlanEnvironment> { state, action, environment in
switch action {
case .startStage(stage: let stage, stageIndex: let index):
return .none
}
}
2 Likes
fmCarlos
(Carlos)
4
That makes sense, thanks a lot @mayoff I'll give that a go!