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

SwiftUI跨视图传递product_id异常:首次打开Sheet无值

问题分析:首次打开Sheet时product_id传递失效的原因及解决办法

项目中用户可拥有两个收藏商品,点击商品后弹出ProductSheet视图,尝试传递前一个视图的product_id到ProductSheet和ProductRowView以实现修改收藏功能,但首次打开Sheet时product_id无值,二次打开正常。

相关代码

FavouriteProducts视图

struct FavouriteProducts: View {
    
    @StateObject var favouriteProductsModel = FavouriteProductsViewModel()
    @State private var showingSheet = false
    @State var selectedProduct: String?
    @State var product_id: String?
        
    
    var body: some View {
        
        ZStack {
            let defaults = UserDefaults.standard
            let keyString: String? = defaults.string(forKey: "key") ?? ""
            
            VStack {
                
                HStack {
                    
                    Text("Tap to change favourite product")
                }
                
                HStack(spacing: 25) {
                    
                    ForEach(favouriteProductsModel.favourite_products, id: \.id){ product in
                        
                        VStack {
                                                                                                
                            Image("ProductImage")
                                .resizable()
                                                    
                            Text(String(product.product_name ?? ""))

                        }
                        .onTapGesture {
                            selectedProduct = product.id
                            self.product_id = product.id ?? ""
                            self.showingSheet = true
//selectedProduct does have a value in this print statement
                            print("Tapped Product ID: \(String(describing: selectedProduct))")
                        }
                        .sheet(item: $selectedProduct) {
                            favouriteProductsModel.fetchFavouriteProducts(key: keyString ?? "")
                        } content: { item in
                            ProductSheet(product_id: selectedProduct ?? "")
                        }
                    }
                }
            }
        }
        .onLoad {
            let defaults = UserDefaults.standard
            let keyString: String? = defaults.string(forKey: "key") ?? ""
            self.favouriteProductsModel.fetchFavouriteProducts(key: keyString ?? "")
        }
    }
}

ProductSheet视图

struct ProductSheet: View {
    
    @StateObject var marketplaceModel = MarketplaceViewModel()
    @State var product_id: String?

    var body: some View {


        VStack {
            
            // The product_id here is not being displayed, because the variable has no value
            Text(product_id ?? "")
            
            ForEach(marketplaceModel.filteredProduct, id:\.self){ product in
                
                ProductRowView(productData: product, product_id: product_id ?? "")
            }
                        
        }
    }
}

ProductRowView视图

struct ProductRowView: View {
    
    @Environment(\.dismiss) var dismiss
    @StateObject var favouriteProductsModel = FavouriteProductsViewModel()
    @State private var isShowingDetailView = false
    @State var selectedProduct : ProductTile?
    @State var new_id = ""
    var productData: ProductRow
    var product_id: String
    
    var body: some View {
        
        VStack {
            
            HStack {
                Text(productData.title)
                
                HStack {
                    NavigationLink("", isActive: $isShowingDetailView) {
                        ProductSeeAllView(productData: productData, product_id: productData.id)
                    }.navigationTitle("")
                    
                    Button("See All") {
                        isShowingDetailView = true
                    }
                    Image(systemName: "chevron.right")
                }
            }
            
            HStack {
                ScrollView {
                    HStack {
                        ForEach(productData.products ?? []) { product in
                            ProductView(productData: product)
                                .onTapGesture {
                                    new_id = product.id ?? ""
                                    selectedProduct = product
                                    print("Product id: \(selectedProduct?.id ?? "")")
                                    let defaults = UserDefaults.standard
                                    let keyString: String? = defaults.string(forKey: "key") ?? ""
                                    
                                    favouriteProductsModel.changeFavouriteProducts(key: keyString ?? "", current_id: product_id, new_id: new_id ) { (success) in
                                        if success {
                                            dismiss()
                                        } else {
                                            print("Unsuccessful...")
                                        }
                                    }
                                }
                        }
                    }
                }
            }
        }
    }
}

原因解析

  1. Sheet初始化时序问题:在FavouriteProducts的.sheet(item:)闭包中,你使用了selectedProduct而不是闭包提供的item参数。SwiftUI首次触发Sheet时,selectedProduct的状态更新和Sheet初始化存在时序差,导致Sheet拿到的是旧的nil值;第二次打开时selectedProduct已有上次的有效值,所以能正常传递。
  2. 错误的状态声明:ProductSheet中将外部传入的product_id声明为@State,@State用于视图内部管理的状态,会忽略外部传入的初始值,默认使用nil,这也是首次打开时无值的核心原因之一。

修复方案

  1. 使用Sheet闭包的item参数传递值:
    修改FavouriteProducts中.sheet的content闭包,直接使用item(即选中的product.id):

    .sheet(item: $selectedProduct) {
        favouriteProductsModel.fetchFavouriteProducts(key: keyString ?? "")
    } content: { item in
        ProductSheet(product_id: item)
    }
    

    同时可以删除FavouriteProducts中多余的product_id状态变量。

  2. 修正ProductSheet的变量声明:
    将ProductSheet中的@State var product_id: String?改为普通变量,因为它是外部传入的常量:

    struct ProductSheet: View {
        
        @StateObject var marketplaceModel = MarketplaceViewModel()
        var product_id: String
        
        // 剩余代码不变
    }
    

这样修改后,SwiftUI会确保Sheet初始化时拿到最新的选中product_id值,同时避免@State覆盖传入值的问题,首次打开Sheet时就能正常传递product_id。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:37:16