Search code examples
swiftswiftuiswiftui-navigationlinkswiftdataios17

SwiftUI - NavigationLink(value: ) and navigationDestination not working


I have a SwiftData model called Diem with variables id, name, and date. I want to navigate from HomeView to DiemDetail, but the NavigationLink does not work. Xcode shows no errors.

struct HomeView: View {
    @Query(sort: \Diem.date) 
    private var diems: [Diem]
    
    var body: some View {
        NavigationStack {
            DiemsGrid()
                .navigationDestination(for: Diem.ID.self) { diemID in
                    if let diem = diems.first(where: { $0.id == diemID }) {
                        DiemDetail(diem: diem)
                    }
                }
        }
    }
}
struct DiemsGrid: View {
    @Query(sort: \Diem.date) var diems: [Diem]

    var body: some View {
        ScrollView(.vertical) {
            LazyVGrid(columns: layout, spacing: 0) {
                ForEach(diems) { diem in
                    DiemGridItem(diem: diem)
                }
            }
        }
    }
}
struct DiemGridItem: View {
    var diem: Diem
    
    var body: some View {
        NavigationLink(value: diem.id) {
            // View code
        }
    }
}

And DiemDetail

struct DiemDetail: View {
    var diem: Diem

    var body: some View {
        NavigationStack {
            VStack() {
                // views
            }
            .toolbar {
                // views
            }
        }
    }
}

The Diem model is all good. I do have a .sheet in DiemDetail and HomeView but I don't think that's the problem.


Solution

  • Firstly, you're having duplicate NavigationStack on both HomeView and DiemDetail. DiemDetail also has navigation from its parent, which is HomeView. Unless you remove it, it will not work, because the first time you have pushed to DiemDetail, navigation will be replaced with the nested one, which does not handle .navigationDestination anymore.

    Secondly, NavigationLink in DiemGridItem takes the correct type, which is mapped with .navigationDestination from its ancestor. However, you did not provide its appearance, that's why you didn't see any tappable links.

    So combine those things:

    struct DiemGridItem: View {
        var diem: Diem
        
        var body: some View {
            NavigationLink(value: diem.id) {
                Text(diem.id.uuidString)
            }
        }
    }
    
    struct DiemDetail: View {
        var diem: Diem
    
        var body: some View {
            VStack {
                ...
            }
            .toolbar {
                ...
            }
        }
    }