nielstj
(Daniel Tjuatja)
1
Question regarding bubbling up action for a deep nested state, for example:
- Handling user authenticated with state structured like this, app > landing> login > 2FA >
A naive approach in app reducer will be :
case let .landing(.login(.twoFactor(.twoFactorResponse(.success(response))))),
let .landing(.login(.loginResponse(.success(response)))) where !response.twoFactorRequired:
...
- Globally handle 401 (unauthorized) response from remote server.
A naive approach will be handling this in every reducer or combine it to bubble it up to app state.
Is there an elegant solution for such scenarios? One way i can think of is using long living effects with notification center and combine it with root/app reducer.
2 Likes
This is what we are trying solve here
Expecting some feedback from author and still we are not sure why Reducer can't return error.
As @grinder81 mentions above we've gone through this exercise for the same reason. We need to handle 401 but also we're showing a toast on errors too. So far, we're able to do this using our own FailableReducer type which returns a failable Effect<Action, Error>. We then implemented (copied) the combine, pullback, etc. functions to make everything work. So all the real reducers are FailableReducer.
At the root of the tree, we have a higher-order reducer which does the catch and performs the error handling. This higher-order reducer is the normal non-failable Reducer which can be passed into the Store:
extension Reducer {
static func errorHandling(
_ reducer: FailableReducer<AppState, AppAction, AppEnvironment>
) -> Reducer<AppState, AppAction, AppEnvironment> {
Reducer { state, action, environment in
reducer(&state, action, environment)
.catch { error -> Effect<AppAction, Never> in
if case APIError.unauthorized = error {
return Effect(value: .handleUnauthorized)
}
return Effect(value: .showError(error))
}
.eraseToEffect()
}
}
}
One thing we've been wondering about is if it can make sense for Reducer to return failable Effect<Action, Error> instead of the non-failing Effect<Action, Never>. We tried on this branch and it seems to work out ok so far, but we're looking for feedback on it. We believe there might be a reason for this - whether it's technical or practical though we're not sure. Hoping it can be possible though as it seems it would make this a bit easier for centralized error handling.
2 Likes
By the way, the other approach we dabbled with was have the reducers return Effect<Result<Action, Error>, Never>. It didn't seem straightforward though so we gave up on it rather early.
nielstj
(Daniel Tjuatja)
6
@sundeepgupta @grinder81 Thank you, will keep watching for update on the branch.