SwiftUI按钮点击后无法按条件跳转至ChatScreen问题
问题描述
点击按钮时希望根据条件跳转至ChatScreen(),点击正确群组时控制台打印“group found”,但实际无法跳转,反而弹出弹窗。
代码示例
List(viewModel.danceGroups) { group in Button(action: { if authViewModel.authenticationState == .authenticated { check(groupId: group.id, userId: authViewModel.uid){ performed in if performed{ goToChatScreen = true }else { showPopup = true } } } else { showSignInSheet = true } }) { VStack(alignment: .leading) { Text(group.groupName) .bold() .font(.title2) Text(hoursAgo(from: TimeInterval(group.timestamp), from: group.isPermanent)) .font(.footnote) .italic() } } .navigationDestination(isPresented: $goToChatScreen){ ChatScreen(groupId: group.id) } } func check(groupId: String, userId: String, completion: @escaping (Bool) -> Void) { let database = Database.database().reference() let GroupsRef = //path GroupsRef.observeSingleEvent(of: .value) { snapshot in if snapshot.exists() { if let joinedDanceGroups = snapshot.value as? [String: Bool], joinedDanceGroups[groupId] == true { print("group found") completion(true) } else { print("group not found") completion(false) } } else { completion(false) } } }
问题分析与解决方案
核心问题1:后台线程更新SwiftUI状态
Firebase的observeSingleEvent回调默认运行在后台队列,直接在回调里更新@State变量(goToChatScreen/showPopup)会导致状态更新无法被视图正确捕获,引发异常行为。
核心问题2:navigationDestination绑定逻辑错误
将navigationDestination附加在List的每个Button上,会导致多个导航目标绑定同一个布尔状态,状态变化时所有对应导航目标都会被触发,引发跳转冲突。
修复步骤:
- 切换主线程更新状态:在
check函数的completion回调中,用DispatchQueue.main.async包裹状态更新代码,确保SwiftUI状态在主线程修改:
check(groupId: group.id, userId: authViewModel.uid){ performed in DispatchQueue.main.async { if performed{ self.selectedGroupId = group.id }else { self.showPopup = true } } }
- 调整导航目标位置:将
navigationDestination从List的Button中移出,放在List外部(如NavigationStack的直接子视图位置),同时改用可选类型的selectedGroupId传递群组ID,替代布尔状态:
@State private var selectedGroupId: String? // 放在List代码块之后 .navigationDestination(item: $selectedGroupId) { groupId in ChatScreen(groupId: groupId) }
- 优化状态逻辑:用
selectedGroupId替代goToChatScreen,通过可选值的有无控制跳转,逻辑更直观,避免布尔状态的歧义。
完整修复后代码片段
@State private var selectedGroupId: String? @State private var showPopup = false @State private var showSignInSheet = false // ... List(viewModel.danceGroups) { group in Button(action: { if authViewModel.authenticationState == .authenticated { check(groupId: group.id, userId: authViewModel.uid){ performed in DispatchQueue.main.async { if performed { selectedGroupId = group.id } else { showPopup = true } } } } else { showSignInSheet = true } }) { VStack(alignment: .leading) { Text(group.groupName) .bold() .font(.title2) Text(hoursAgo(from: TimeInterval(group.timestamp), from: group.isPermanent)) .font(.footnote) .italic() } } } .navigationDestination(item: $selectedGroupId) { groupId in ChatScreen(groupId: groupId) }
额外验证点
- 确认
GroupsRef的路径配置正确,能正常读取用户加入的群组数据。 - 检查
authViewModel.uid是否为有效值,避免因用户ID为空导致查询错误。
内容的提问来源于stack exchange,提问作者Deepanshu Kashyap
相关产品推荐
相关产品推荐

