Introduce NavigationStackBound as a fix for unpredictable ContainerLifecycle calls#107
Merged
Merged
Conversation
Sashe0
reviewed
May 19, 2026
Sashe0
reviewed
May 19, 2026
Sashe0
approved these changes
May 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This merge request introduces a dedicated
NavigationStackBoundSwiftUI wrapper to fix unstableNavigationStackbehavior when the navigation path is exposed from UDF state through reconstructedBinding(get:set:)instances.The issue occurs because
NavigationStackis sensitive to binding identity. When a container remaps the path binding on every state update, SwiftUI may re-traverse the navigation tree during active transitions, causing unintended descendant lifecycle effects such as duplicate@StateObjectinitialization and incorrectonContainerDidLoad/onContainerDidUnloadcalls.Instead of moving navigation state ownership away from UDF, this approach keeps the external binding as the source of truth and stabilizes only the binding presented to
NavigationStack. The alternative would have been to redesign navigation ownership or add explicit synchronization flags, but this solution isolates the problem at the view boundary with minimal impact on existing state flow.Changes Made
NavigationStackBound<Root: View>component inUDF/View/Router/NavigationStackBound.swift.Binding<NavigationPath>with:@Binding private var external@State private var localNavigationStackusing the stable local binding: