I'm currently trying to think about how to best model the display of errors within our app and I'm struggling to come up with the right approach.
There is some prior art and ideas already available, such as the built-in alert/action sheet functionality in TCA and also some previous discussion here:
The simple approach would be, for a given module (e.g. FeatureAState
, FeatureAAction
), to have that feature's state have some kind of banner
or alert
property but there seems to be some limitations around modelling things this way:
- You need to repeat this everywhere - duplicating properties and actions in each model that needs to display some kind of error alert.
- You need to repeat the UI code so each view reacts to this duplicate state and displays the appropriate UI.
- It potentially allows for an invalid state across your application.
The last point in particular is what makes me feel like modelling state in this way is not the right approach. Correctly modelled state should not allow you to create an invalid combination of states. Its why we might use enum
to represent exclusive states rather than a mix of properties on a struct
for 'example. So how does it apply here? Conceptually, for most apps, you can only be displaying a single banner or error alert at a time, across your whole app. On iOS, this is especially true for alerts.
So how is your UI supposed to react if you have struct FeatureA
and struct FeatureB
both with an alert
property and both set to some value? There is no way to enforce the idea that only one alert can be set across your entire state tree at a time modelled this way.
The obvious way to model this would be for there to be a single state property in your root AppState
however you're now faced with the issue of how you bubble error states up from your child reducers. They cannot directly set the app state, nor can they return an effect that sends some root action.
Is the only way to approach this to have a combination of both? Have a single root alert state that you then share across your sub-states so that sub-states just mutate their own local state but this state mutation is just a proxy for mutating the root state, as in the "Shared State" case study?
This would seem to solve the "invalid state" problem and would also seem to solve the duplicate UI code as you could have your root AppView
react to the changes on the AppState
. It would however still need you to add a property to each child state and then a significant amount of boilerplate in your app state to derive the child state from the shared state.
Another problem with this approach is that whilst you can only have one alert at a time, you may want those alerts to behave in different ways but it the AlertState
can only be generic over a single ActionType
.
Is there a better approach that I'm missing?