SwiftUI NavigationLink goes back immediately on first activation after app launch

I am experiencing an issue with programmatic navigation in my SwiftUI app. I use a NavigationLink with an isActive binding to navigate to a specific view (EditUser). The first time I toggle the binding (navigateToEditUser) after the app launches, the navigation occurs but immediately goes back. On subsequent activations, it works as expected. This issue repeats every time I restart the app.

Here is the relevant code snippet:

NavigationLink(
    destination: EditarUsuario(),
    isActive: $navigateToEditUser
) {
    EmptyView()
}

The binding (navigateToEditUser) is toggled from within a .sheet like this:

.onNavigateToEditUserData: {
    navigateToEditUser = true
}

I have tried:

None of these solutions have resolved the problem. I suspect it might be related to how SwiftUI re-renders the view hierarchy or handles NavigationLink's isActive state during initialization.

What could be causing this behaviour, and how can I ensure consistent navigation without the first activation issue?

Providing more details about full navigation flow:

struct compactNavigation: View {

    @EnvironmentObject var state: AppState

    var handler: Binding<String?> { Binding(
        get: { state.selectedTab },
        set: {
            let tab = state.selectedTab
            if $0 == tab {
                state.resetTab.toggle()
                print("Reset tab")
            } else {
                Tutorial.shared.stop()
            }
            state.selectedTab = $0
        }
    )}

    var body: some View {
        TabView(selection: handler) {
            NavigationView {
                Settings()
            }
            .tabItem { Label("settings", systemImage: "gearshape.fill") }
            .tag(Settings.tag)
        }
    }

}


struct Settings: View {
    var body: some View {
        Form {
            Section(header: Text("account")) {
                NavigationLink(destination:
                    PlanView()
                ) {
                    Text("plan")
                        .font(.headline)
                }
            }
        }
    }
}


struct PlanView: View {

    @State var showFilterEditor = false
    @State var navigateToEditUser = false

    var body : some View {
        ScrollView {
            VStack {
                NavigationLink(
                    destination: EditarUsuario(),
                    isActive: $navigateToEditUser
                ) {
                    EmptyView()
                }
                // Rest of the view content...
            }
        }
        .toolbar(content: {
            ToolbarItem(placement: .navigationBarTrailing){
                Button(action: {
                    showFilterEditor.toggle()
                }, label: {
                    Label(title: { Text("filter") },
                          icon: { Image(systemName: "slider.horizontal.3") })
                })
            }
        })
        .sheet(isPresented: $showFilterEditor, content: {
            NutritionalPlanParameterEditor(
                onNavigateToEditUserData: {
                    navigateToEditUser = true
                }
            )
        })
    }
}

Upvotes: 0

Views: 105

Answers (1)

K.pen
K.pen

Reputation: 343

Combine NavigationLink with onAppear If you must use NavigationLink and a binding, reset the binding value in onAppear of the destination view:

NavigationLink(
    destination: EditarUsuario().onAppear {
        navigateToEditUser = false
    },
    isActive: $navigateToEditUser
) {
    EmptyView()
}

This ensures the navigation state (navigateToEditUser) resets correctly once the destination view appears.

Upvotes: 0

Related Questions