@@ -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 }
@@ -657,9 +660,16 @@ public struct _PresentationReducer<Base: Reducer, Destination: Reducer>: Reducer
657660 baseEffects = self.base.reduce(into: &state, action: action)
658661 }
659662
663+ let currentNavigationID = state[keyPath: self.toPresentationState].wrappedValue.map(self.navigationIDPath(for:))
664+ let storedEffectPath = initialPresentationState.effectNavigationIDPath
665+
666+ // Detect parent context change: if effectNavigationIDPath is nil but presentation exists,
667+ // it means COW occurred (effectNavigationIDPath was cleared in wrappedValue setter)
668+ let parentContextChanged = currentNavigationID != nil
669+ && (storedEffectPath == nil || storedEffectPath != currentNavigationID)
670+
660671 let presentationIdentityChanged =
661- initialPresentationState.presentedID
662- != state[keyPath: self.toPresentationState].wrappedValue.map(self.navigationIDPath(for:))
672+ initialPresentationState.presentedID != currentNavigationID
663673
664674 let dismissEffects: Effect<Base.Action>
665675 if presentationIdentityChanged,
@@ -676,14 +686,22 @@ public struct _PresentationReducer<Base: Reducer, Destination: Reducer>: Reducer
676686
677687 if presentationIdentityChanged, state[keyPath: self.toPresentationState].wrappedValue == nil {
678688 state[keyPath: self.toPresentationState].presentedID = nil
689+ state[keyPath: self.toPresentationState].effectNavigationIDPath = nil
679690 }
680691
681692 let presentEffects: Effect<Base.Action>
682- if presentationIdentityChanged || state[keyPath: self.toPresentationState].presentedID == nil,
693+ // Recreate Empty effect if:
694+ // - Parent context changed (COW occurred during enum transition)
695+ // - Presentation identity changed (normal navigation)
696+ // - First time presenting (presentedID is nil)
697+ if (parentContextChanged
698+ || presentationIdentityChanged
699+ || state[keyPath: self.toPresentationState].presentedID == nil),
683700 let presentationState = state[keyPath: self.toPresentationState].wrappedValue,
684701 !isEphemeral(presentationState)
685702 {
686703 let presentationDestinationID = self.navigationIDPath(for: presentationState)
704+ state[keyPath: self.toPresentationState].effectNavigationIDPath = presentationDestinationID
687705 state[keyPath: self.toPresentationState].presentedID = presentationDestinationID
688706 presentEffects = .concatenate(
689707 .publisher { Empty(completeImmediately: false) }
0 commit comments