Search code examples
iosswiftswiftuiswiftui-navigationstack

SwiftUI NavigationStack: Unexpected Navigation Behavior from List View


I'm building an iOS app with SwiftUI and am encountering unexpected behaviour when navigating from a List view to a detail view.

I have three views: ViewA, ViewB, and ViewC. ViewA navigates to ViewB, which is a list of Item instances. Tapping on an Item in ViewB should navigate to ViewC, presenting the details of the selected Item.

The navigation to ViewC is misbehaving. When I tap an Item in ViewB, ViewC is shown briefly and then the view immediately navigates back to ViewB. The navigation stack has ViewC before ViewB. Stack: [ViewA, ViewC, ViewB]

The minimal reproducible example:

struct Item: Identifiable, Hashable {
    let id = UUID()
    let title: String
    let description: String
}

struct ViewA: View {
    var body: some View {
        NavigationStack {
            NavigationLink("Go to ViewB") {
                ViewB()
            }
        }
    }
}

struct ViewB: View {
    let items: [Item] = [
        Item(title: "Item 1", description: "This is item 1"),
        Item(title: "Item 2", description: "This is item 2")
    ]
    
    var body: some View {
        List(items, id: \.id) { item in
            NavigationLink(value: item) {
                Text(item.title)
            }
        }
        .navigationDestination(for: Item.self) { item in
            ViewC(item: item)
        }
    }
}

struct ViewC: View {
    let item: Item

    var body: some View {
        Text(item.description)
    }
}

I expect to navigate directly to ViewC when an Item is selected in ViewB and the back button should take me back to ViewB. The stack should be [ViewA (root), ViewB, ViewC].

What caused the misbehaviour and how can I resolve this?


Solution

  • You can modify the code of ViewB as follows:

    struct ViewB: View {
        let items: [Item] = [
            Item(title: "Item 1", description: "This is item 1"),
            Item(title: "Item 2", description: "This is item 2")
        ]
        
        var body: some View {
            List(items) { item in
                NavigationLink {
                    ViewC(item: item)
                } label: {
                    Text(item.title)
                }
            }
        }
    }