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

SwiftUI中onReceive无法触发NavigationLink实现Firebase登录后导航

SwiftUI + Firebase登录后无法导航到主页的解决方案

问题出在你用onReceive回调创建NavigationLink的方式——SwiftUI的视图必须存在于视图树中才能生效,回调里临时创建的NavigationLink不会被渲染,所以导航触发不了,这也是为什么控制台能打印但页面没跳转的原因。

修复步骤:

  1. 调整ViewModel的登录状态赋值:
    把self.isSignedIn.toggle()改成直接赋值true,避免重复登录时状态反转的问题(比如用户退出后再次登录,toggle会把已登录的true又改成false)。

  2. 在视图树中添加受控的NavigationLink:
    将NavigationLink放在NavigationView内部的视图层级里,通过绑定viewModel.isSignedIn来控制导航激活状态,并且隐藏这个链接(因为我们不需要显示点击入口,只是用它触发自动导航)。

修改后的代码:

LoginViewModel

class LoginViewModel: ObservableObject {
    let auth = Auth.auth()
    var userInfo: User?
    
    @Published var isSignedIn = false
    
    func signIn(email: String, password: String) {
        auth.signIn(withEmail: email, password: password) { _, error in
            if let error = error as? NSError {
                print("Error happened on login"+error.description)
            } else {
                print("Login successful")
                if let user = self.auth.currentUser {
                    print("We have a user")
                    self.userInfo = user
                    // 直接赋值为true,替代toggle避免状态异常
                    self.isSignedIn = true
                }
            }
        }
    }
}

LoginPage

struct LoginPage: View {
    @State var email = ""
    @State var password = ""

    @ObservedObject var viewModel = LoginViewModel()

    var body: some View {
        NavigationView {
            ZStack {
                VStack {
                    TextField("Email", text: $email).padding()
                        .background(Color(.secondarySystemBackground))
                        .padding()
                    TextField("Password", text: $password).padding()
                        .background(Color(.secondarySystemBackground))
                        .padding()
                    Button(action: {
                        guard !email.isEmpty, !password.isEmpty else {
                            return
                        }
                        viewModel.signIn(email: email, password: password)

                    }, label: {
                        Text("Sign in")
                            .padding(EdgeInsets(top: 12, leading: 35, bottom: 12, trailing: 35))
                            .foregroundColor(.white)
                            .background(Color.blue)
                            .cornerRadius(15)
                    })
                }
                // 添加受控的NavigationLink,隐藏在视图中
                NavigationLink(
                    destination: HomePage(),
                    isActive: $viewModel.isSignedIn,
                    label: { EmptyView() }
                )
                .hidden()
            }.navigationTitle("Login")
        }
        // 保留onReceive做打印或其他逻辑(可选)
        .onReceive(viewModel.$isSignedIn) { isSignedIn in
            if isSignedIn {
                print("ok damm")
            }
        }
    }
}

额外说明:

  • 如果你需要在用户退出时返回登录页,只需要在HomePage里将viewModel.isSignedIn设为false即可,这个绑定会自动触发导航返回。
  • 建议用@StateObject替代@ObservedObject来初始化LoginViewModel(iOS 14+),确保ViewModel的生命周期和视图一致:@StateObject var viewModel = LoginViewModel()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:45:49