@@ -57,6 +57,8 @@ public struct PresentationState<State> {
5757
5858 private var storage : Storage
5959 @usableFromInline var presentedID : NavigationIDPath ?
60+ // Tracks navigation path when effect was created. Cleared on COW to detect parent context changes.
61+ @usableFromInline var effectNavigationIDPath : NavigationIDPath ? = nil
6062
6163 public init ( wrappedValue: State ? ) {
6264 self . storage = Storage ( state: wrappedValue)
@@ -67,6 +69,7 @@ public struct PresentationState<State> {
6769 set {
6870 if !isKnownUniquelyReferenced( & self . storage) {
6971 self . storage = Storage ( state: newValue)
72+ self . effectNavigationIDPath = nil // Clear on COW to trigger effect recreation
7073 } else {
7174 self . storage. state = newValue
7275 }
@@ -586,6 +589,9 @@ public struct _PresentationReducer<Base: Reducer, Destination: Reducer>: Reducer
586589 public func reduce( into state: inout Base . State , action: Base . Action ) -> Effect < Base . Action > {
587590 let initialPresentationState = state [ keyPath: self . toPresentationState]
588591 let presentationAction = self . toPresentationAction. extract ( from: action)
592+
593+ // Capture the navigation ID BEFORE any state changes (like StackReducer does with idsBefore)
594+ let navigationIDBeforeReduce = initialPresentationState. wrappedValue. map ( self . navigationIDPath ( for: ) )
589595
590596 let destinationEffects : Effect < Base . Action >
591597 let baseEffects : Effect < Base . Action >
@@ -657,9 +663,24 @@ public struct _PresentationReducer<Base: Reducer, Destination: Reducer>: Reducer
657663 baseEffects = self . base. reduce ( into: & state, action: action)
658664 }
659665
666+ let navigationIDAfterReduce = state [ keyPath: self . toPresentationState] . wrappedValue. map ( self . navigationIDPath ( for: ) )
667+ let storedEffectPath = initialPresentationState. effectNavigationIDPath
668+
669+ // Detect parent context change (e.g., enum case transition via COW)
670+ let parentContextChanged : Bool
671+ if let current = navigationIDAfterReduce {
672+ if let stored = storedEffectPath {
673+ parentContextChanged = stored != current
674+ } else {
675+ parentContextChanged = true // nil path + existing presentation = COW occurred
676+ }
677+ } else {
678+ parentContextChanged = false
679+ }
680+ let navigationContextChanged = navigationIDBeforeReduce != navigationIDAfterReduce
681+
660682 let presentationIdentityChanged =
661- initialPresentationState. presentedID
662- != state [ keyPath: self . toPresentationState] . wrappedValue. map ( self . navigationIDPath ( for: ) )
683+ initialPresentationState. presentedID != navigationIDAfterReduce
663684
664685 let dismissEffects : Effect < Base . Action >
665686 if presentationIdentityChanged,
@@ -676,14 +697,24 @@ public struct _PresentationReducer<Base: Reducer, Destination: Reducer>: Reducer
676697
677698 if presentationIdentityChanged, state [ keyPath: self . toPresentationState] . wrappedValue == nil {
678699 state [ keyPath: self . toPresentationState] . presentedID = nil
700+ state [ keyPath: self . toPresentationState] . effectNavigationIDPath = nil
679701 }
680702
681703 let presentEffects : Effect < Base . Action >
682- if presentationIdentityChanged || state [ keyPath: self . toPresentationState] . presentedID == nil ,
704+ // Recreate Empty effect if:
705+ // - Parent context changed (e.g., enum case transition)
706+ // - Navigation context changed (normal navigation)
707+ // - Presentation identity changed
708+ // - First time presenting (presentedID is nil)
709+ if ( parentContextChanged
710+ || navigationContextChanged
711+ || presentationIdentityChanged
712+ || state [ keyPath: self . toPresentationState] . presentedID == nil ) ,
683713 let presentationState = state [ keyPath: self . toPresentationState] . wrappedValue,
684714 !isEphemeral( presentationState)
685715 {
686716 let presentationDestinationID = self . navigationIDPath ( for: presentationState)
717+ state [ keyPath: self . toPresentationState] . effectNavigationIDPath = presentationDestinationID
687718 state [ keyPath: self . toPresentationState] . presentedID = presentationDestinationID
688719 presentEffects = . concatenate(
689720 . publisher { Empty ( completeImmediately: false ) }
0 commit comments