SwiftUI drag to dismiss crash

We might need to figure out how to better document this, but reducer ordering is very important, and the rule of thumb is you almost always want to run local reducers before more global ones.

In your example it is tempting to have a local close action that a parent hooks into but does nothing on its own in the child reducer. While this seems perfectly reasonable, and makes it sound like the order of the combine doesn't matter, if you come back to this code later and try to instrument it so that the local reducer fires off an effect when it receives close you will have a bug on your hands if the global reducer runs first:

  1. Global reducer intercepts .close and nils out state
  2. Local reducer cannot run with optional state so .close logic is never run

This is why we prefer to crash here and not silently ignore actions sent to optional reducers, because it almost always means that there's a bug just waiting to happen. For instance, in the thread mentioned above, the precondition caught the fact that timer cancellation was not actually happening.

Also in that thread @mbrandonw has shared a higher-order reducer that may make it easier to reason about these kinds of onAppear and onDisappear lifecycle-y reducers: IfLetStore and Effect cancellation on view disappear - #2 by mbrandonw