I was thinking of this too! I would like to "run an action" on other reducer when a value in the global state changes. Maybe some sort of pullback like reducer could be done? If each substate would have their own loadingState and a generic reducer would route the changes.
public func onChange<GlobaState, State, GlobalAction, Environment>(
state: KeyPath<GlobaState, State>,
sendChangeAs: @escaping (State) -> GlobalAction
) -> Reducer<GlobaState, GlobalAction, Environment> where State: Equatable {
var oldState: State?
return Reducer<GlobaState, GlobalAction, Environment> { (globalState, _, env) in
let newState = globalState[keyPath: state]
defer { oldState = newState }
return newState != oldState
? pure(sendChangeAs(newState))
: .none
}
}
where one would have actions for the change on each module like
struct AppState {
var stateA: StateA
var stateB: StateB
}
enum AppAction {
case actionA(ActionA)
case actionB(ActionB)
}
enum ActionA {
case doStuffToChangeLoadingState
}
enum ActionB {
case loadingStateChanged(LoadingState)
}
then changes would be routed in the combined app reducer:
let aReducer = Reducer<StateA, ActionA, ...>(...)
let bReducer = Reducer<StateB, ActionB, ...>(...)
let appReducer = Reducer<AppState, AppAction, ...>.combine(
onChange( // Routes changes from StateA.loadingState to StateB.loadingState as an action
state: \AppState.stateA.loadingState,
sendChangeAs: { AppAction.actionB(.loadingStateChanged($0) }
),
aReducer.pullback( // Regular pullback for actually changing the LoadingState
state: \AppState.stateA,
action: /AppAction.actionA
),
bReducer.pullback( // Regular pullback for StateB
state: \AppState.stateB,
action: /AppAction.actionB
)
)
The onChange reducer is one way though so if ReducerB would change LoadingState it would not go to StateA. The advantage here would be that StateA and B do not need to be computed properties in AppState. Disadvantage is that the routing is pushed to reducer and each submodule needs to have duplicate actions and handling of change of LoadingState. I'm not sure if this could be further refined.