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

如何在ForEach中结合navigationDestination实现页面跳转?求优化方案

优化SwiftUI通知列表跳转逻辑的实现方案

原代码存在的问题

  • 依赖索引遍历列表,数据变动时易引发视图识别错误(比如增删通知后,索引对应的元素可能不匹配)
  • 所有单元格共用同一个moveToApptDetailView状态变量,可能导致跳转逻辑混乱
  • 直接在ApptDetailView初始化时创建ApptHistoryViewModel,不利于测试和状态管理
  • 额外维护appointment临时变量,增加状态复杂度

优化后的实现方案

假设Notification遵循Identifiable协议(如果没有,建议给每个通知添加唯一标识属性,比如id: UUID),优化代码如下:

// 在父视图中定义可选的选中预约状态
@State private var selectedAppointment: Appointment?

var body: some View {
    List {
        ForEach(viewModel.notifications) { notification in
            NotificationCellView(notification: notification) { type in
                switch type {
                case .refund:
                    // 直接赋值选中的预约,触发跳转
                    selectedAppointment = notification.appointment
                case .makePayment:
                    debugPrint("notification makePayment pressed")
                case .none:
                    debugPrint("notification none pressed")
                }
            }
        }
    }
    // 将navigationDestination提升到列表外层,统一处理跳转
    .navigationDestination(item: $selectedAppointment) { appointment in
        ApptDetailView(appt: .constant(appointment), viewModel: viewModel.apptHistoryViewModel)
            .hideNavigationBar
    }
}

进一步优化建议

  1. 状态管理优化
    如果ApptHistoryViewModel需要依赖当前预约数据,建议在父视图中根据选中的预约创建或配置ViewModel,而非直接初始化空实例:
    .navigationDestination(item: $selectedAppointment) { appointment in
        let detailVM = ApptHistoryViewModel(appointment: appointment)
        ApptDetailView(appt: appointment, viewModel: detailVM)
            .hideNavigationBar
    }
    
  2. Cell回调简化
    如果.refund是唯一需要跳转的操作,可以让NotificationCellView直接返回需要跳转的Appointment?,简化回调逻辑:
    // NotificationCellView定义
    struct NotificationCellView: View {
        let notification: Notification
        var onJumpToAppointment: ((Appointment?) -> Void)?
        
        // Cell内容中触发操作时调用
        // 示例:refund按钮点击事件
        Button("申请退款") {
            onJumpToAppointment?(notification.appointment)
        }
    }
    
    // 父视图中使用
    NotificationCellView(notification: notification) { appointment in
        if let appointment = appointment {
            selectedAppointment = appointment
        } else {
            debugPrint("其他操作触发")
        }
    }
    
  3. 避免不必要的绑定
    如果ApptDetailView不需要修改appointment数据,建议传递不可变的Appointment而非绑定,减少冗余状态传递:
    // 修改ApptDetailView的初始化参数
    struct ApptDetailView: View {
        let appt: Appointment
        let viewModel: ApptHistoryViewModel
        
        // 视图内容
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 18:43:37