You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中NavigationLink无法正常跳转问题求助

SwiftUI中NavigationLink无法在Firebase数据上传后跳转的问题解决

问题根源

你的代码核心错误是将Button嵌套在NavigationLink的label中,点击时会同时触发两个逻辑:

  • NavigationLink立即执行页面跳转
  • Button执行Firebase异步上传

这就导致还没等数据上传完成,页面已经跳转到UserDashboard,完全违背了“先上传再跳转”的需求,同时这种嵌套交互控件的写法本身就不符合SwiftUI的设计规范。

解决方案:使用编程式导航

我们需要通过状态变量控制导航时机,确保只有在Firebase上传成功后才触发跳转,具体步骤如下:

  1. 添加导航状态变量
    在视图的@State属性中新增一个布尔变量,用于控制导航是否触发:
@State private var shouldNavigateToDashboard = false
  1. 替换原NavigationLink为状态控制的隐藏版本
    将原来的嵌套式NavigationLink替换为受状态变量控制的隐藏链接,放在视图的VStack或ScrollView外层(确保它在NavigationStack范围内):
// 放在ScrollView之后、VStack内部
NavigationLink(
    destination: UserDashboard().navigationBarBackButtonHidden(true),
    isActive: $shouldNavigateToDashboard,
    label: { EmptyView() }
)
  1. 重构“Enregistrer”按钮为独立控件
    移除原有的NavigationLink嵌套,直接使用Button执行上传逻辑,在上传成功后修改状态变量触发导航:
Button {
    let prospect = ProspectModel()
    Task {
        do {
            // 等待Firebase上传完成
            try await prospect.enregistrementProspect(
                service: service, 
                categorie: categorie, 
                nom: nom, 
                email: email, 
                tel: tel, 
                adress: adress, 
                siret: siret
            )
            // 上传成功后触发导航
            shouldNavigateToDashboard = true
        } catch {
            // 可在此添加错误处理,比如弹窗提示用户上传失败
            print("Prospect上传失败:\(error.localizedDescription)")
        }
    }
} label: {
    HStack {
        Text("Enregistrer").fontWeight(.semibold)
        Image(systemName: "arrow.right")
    }
    .foregroundColor(.white)
    .frame(maxWidth: .infinity, minHeight: 48)
}
.background(Color(.systemBlue))
.cornerRadius(10)
.padding(.top, 24)

完整修改后的代码

import SwiftUI
import Firebase

struct UserProspect: View {
    @State private var service = ""
    @State private var categorie = ""
    @State private var nom = ""
    @State private var email = ""
    @State private var tel = ""
    @State private var adress = ""
    @State private var siret = ""
    // 新增导航控制状态
    @State private var shouldNavigateToDashboard = false
    
    @EnvironmentObject var viewModel: AuthViewModel
    
    var body: some View{
        content
    }
    
    var content: some View {
        NavigationStack {
            VStack(spacing: 0) {
                Rectangle()
                    .fill(LinearGradient(colors: [.blue, .teal], startPoint: .topLeading, endPoint: .bottomTrailing))
                    .frame(height: 140).offset(y:-60)
                    .overlay(
                        Text("Recommandation")
                            .foregroundColor(.white)
                            .font(.system(size: 38, weight: .bold, design: .rounded))
                            .padding(.top, -50)
                    )
                    .padding(.bottom, 0)
                
                ScrollView {
                    VStack(alignment: .leading, spacing: 10) {
                        SelectorView(title: "Type Service", service: $service, pro: "Professionnel", part: "Particulier")
                        
                        SelectorView(title: "Type de categorie", service: $categorie, pro: "Déménagement", part: "Transport")
                        
                        InputView(text: $nom, title: "Nom", placeholder: "Nom à contacter")
                        
                        InputView(text: $email, title: "Email", placeholder: "Email à contacter")
                        
                        InputView(text: $tel, title: "Téléphone", placeholder: "Téléphone à contacter")
                        
                        InputView(text: $adress, title: "Adresse", placeholder: "Adresse complète")
                        
                        if service == "Professionnel" {
                            InputView(text: $siret, title: "Siret", placeholder: "Siret de l'entreprise")
                        }

                        // 重构后的独立按钮
                        Button {
                            let prospect = ProspectModel()
                            Task {
                                do {
                                    try await prospect.enregistrementProspect(
                                        service: service, 
                                        categorie: categorie, 
                                        nom: nom, 
                                        email: email, 
                                        tel: tel, 
                                        adress: adress, 
                                        siret: siret
                                    )
                                    shouldNavigateToDashboard = true
                                } catch {
                                    print("上传失败:\(error.localizedDescription)")
                                }
                            }
                        } label: {
                            HStack {
                                Text("Enregistrer").fontWeight(.semibold)
                                Image(systemName: "arrow.right")
                            }
                            .foregroundColor(.white)
                            .frame(maxWidth: .infinity, minHeight: 48)
                        }
                        .background(Color(.systemBlue))
                        .cornerRadius(10)
                        .padding(.top, 24)
                            

                        NavigationLink {
                            ContentView().navigationBarBackButtonHidden(true)
                        } label: {
                            Text("Je n'ai finalement pas d'enregistrement")
                                .fontWeight(.bold)
                                .font(.system(size: 14))
                                .frame(maxWidth: .infinity, alignment: .center)
                        }
                    }
                    .padding(.horizontal)
                }
                
                // 隐藏的状态控制导航链接
                NavigationLink(
                    destination: UserDashboard().navigationBarBackButtonHidden(true),
                    isActive: $shouldNavigateToDashboard,
                    label: { EmptyView() }
                )
            }
            .background(Color.white.ignoresSafeArea())
            .navigationBarHidden(true)
        }
    }
}


struct UserProspect_Previews: PreviewProvider {
    static var previews: some View{
        UserProspect()
    }
}

补充说明

页面中的两个NavigationLink本身不会导致运行问题,第二个链接的写法是正确的(因为它不需要异步操作,直接触发跳转)。核心问题出在第一个链接的嵌套写法上,改用编程式导航后就能实现“先上传再跳转”的需求。

内容的提问来源于stack exchange,提问作者Windows Frame

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 18:44:50