If I have a detail view, it can include a NavigationLink (with either a specific destination view, or a value to be resolved by the nearest .navigationDestination handler in to a view).
But some operations cannot be captured by a NavigationLink. For example, perhaps this detail view is editing a list, and I have a button to insert a new item. I may wish to insert the new item, and then navigate to a further editor for the inserted item.
I can't do that with a NavigationLink:
NavigationLink {
// 🚨 This is a @ViewBuilder/@ContentBuilder, and there are no guarantees about how often it is invoked.
let newItem = dataSource.insertNewItem()
ItemEditor(newItem)
} label: {
// ...
}
This is the use-case which NavigationPath or typed navigation stacks handle for us:
Button {
let newItem = dataSource.insertNewItem()
navigationPath.append(newItem)
} label: {
// ...
}
.navigationDestination(for: Item.self) { item in
ItemEditor(item)
}
Unfortunately, while NavigationLink is able to inspect the View's environment, find the nearest NavigationStack, and push to it, there is no built-in @Environment key for programmatic navigation to do the same. Instead, developers need to add the path as an explicit state variable where the stack is declared, and manually pass it around or create their own @Environment keys, being diligent to ensure they always set that environment value in case some detail view happens to need to need programmatic navigation.
I've never understood why. This seems to be a common problem in the ecosystem, and of course in UIKit you can always grab the nearest .navigationController, so I always thought it was an intentional omission.
Was it? Should I file an enhancement request? Or is there a reason why this is not considered a good idea?
Thanks