I am trying to implement a view that is updated by a long-time-running effect - a timer. The view should be presented inside another view which decides if the view with a timer should be presented or not, based on its state.
This may sound a bit complex or hard to understand, so I made an example project and I am sharing it on GitHub: GitHub - darrarski/tca-ifletstore-effect-cancellation-demo
When the view with timer appears, the timer is started by sending an action to the store. When the view with timer disappears I would like the timer to stop, so I am sending another action to the store, that should cancel the effect.
The problem is that the view with timer sits inside IfLetStore
view and when it disappears, its state is already nil
which triggers the following error:
Fatal error: "DetailAction.stopTimer" was received by an optional reducer when its state was "nil". This can happen for a few reasons:
* The optional reducer was combined with or run from another reducer that set "DetailState" to "nil" before the optional reducer ran. Combine or run optional reducers before reducers that can set their state to "nil". This ensures that optional reducers can handle their actions while their state is still non-"nil".
* An active effect emitted this action while state was "nil". Make sure that effects for this optional reducer are canceled when optional state is set to "nil".
* This action was sent to the store while state was "nil". Make sure that actions for this reducer can only be sent to a view store when state is non-"nil". In SwiftUI applications, use "IfLetStore".
I am not sure how should we handle such cases, and how the long-running-effects should be canceled.
Thanks in advance for any hints or ideas!