Viktor Malyi
Viktor Malyi

Reputation: 2386

SwiftUI: NavigationLink pops immediately if used within ForEach

I'm using a NavigationLink inside of a ForEach in a List to build a basic list of buttons each leading to a separate detail screen.

When I tap on any of the list cells, it transitions to the detail view of that cell but then immediately pops back to the main menu screen.

Not using the ForEach helps to avoid this behavior, but not desired.

Here is the relevant code:

struct MainMenuView: View {

    ...

    private let menuItems: [MainMenuItem] = [
        MainMenuItem(type: .type1),
        MainMenuItem(type: .type2),
        MainMenuItem(type: .typeN),
    ]

    var body: some View {
        List {
            ForEach(menuItems) { item in
                NavigationLink(destination: self.destination(item.destination)) {
                    MainMenuCell(menuItem: item)
                }
            }
        }
    }

    // Constructs destination views for the navigation link
    private func destination(_ destination: ScreenDestination) -> AnyView {
        switch destination {
        case .type1:
            return factory.makeType1Screen()
        case .type2:
            return factory.makeType2Screen()
        case .typeN:
            return factory.makeTypeNScreen()
        }
    }

Upvotes: 15

Views: 6598

Answers (3)

Leszek Szary
Leszek Szary

Reputation: 10308

I had a similar problem caused by UUID in id property of used model and what worked for me was changing the navigation link from:

ForEach(model) { model in
    NavigationLink {
        [...]
    } label: {
        MenuRow(model: model)
    }
}

into something like this:

ForEach(model.indices, id: \.self) { index in
    NavigationLink {
        [...]
    } label: {
        MenuRow(model: model[index])
    }
}

Upvotes: 0

HanmuYou
HanmuYou

Reputation: 1

Maybe I found the reason of this bug...

if you use iOS 15 (not found iOS 14), and you write the code NavigationLink to go to same View in different locations in your projects, then this bug appear.

So I simply made another View that has different destination View name but the same contents... then it works..

you can try....

sorry for my poor English...

Upvotes: 0

gujci
gujci

Reputation: 1284

If you have a @State, @Binding or @ObservedObject in MainMenuView, the body itself is regenerated (menuItems get computed again) which causes the NavigationLink to invalidate (actually the id change does that). So you must not modify the menuItems arrays id-s from the detail view.

If they are generated every time consider setting a constant id or store in a non modifying part, like in a viewmodel.

Upvotes: 14

Related Questions