SwiftUI detail sheet传递列表项时子视图值更新异常问题求解
问题根源
你使用的sheet(isPresented:content:)API存在值捕获机制的缺陷:该API的content闭包会在主视图首次渲染时就完成初始值捕获,后续你修改selectedShoppingList变量时,已创建的sheet闭包不会自动更新捕获的值,因此首次弹出时拿到的是默认的ShoppingList.single,关闭sheet后第二次弹出才会读取到更新后的值,这是SwiftUI sheet的常见适配问题。
解决方案
方案1(推荐):改用sheet(item:content:)API
该API专为依赖选中项的弹窗场景设计,选中项变化时会自动重建sheet,永远传入最新的选中值,无需手动维护弹窗显隐状态:
- 首先调整
selectedShoppingList为可选类型,同时删除多余的presentCreateSheet状态:
@State var selectedShoppingList: ShoppingList? // 无需再声明presentCreateSheet
- 修改按钮点击逻辑,直接赋值选中项即可,系统会自动触发弹窗:
Button { self.selectedShoppingList = shoppingList } label: { HomeRowView(shoppingList: shoppingList) }
- 替换原有sheet实现:
.sheet(item: $selectedShoppingList, onDismiss: { Task { await viewModel.getList() } }, content: { selectedList in // 每次弹出都会用最新的选中值初始化ViewModel ItemView(viewModel: ItemViewModel(shoppingList: selectedList)) })
注意:需要让
ShoppingList遵守Identifiable协议,若暂未适配,也可以使用sheet(item: $selectedShoppingList, id: \.self)的写法(需保证ShoppingList遵守Hashable协议)。
方案2:强制刷新sheet内容
如果不想改动现有代码结构,可以给sheet内的根View绑定唯一标识,每次选中项变化时强制重建View:
.sheet(isPresented: $presentCreateSheet, onDismiss: { Task.init { await viewModel.getList() } self.presentCreateSheet = false }, content: { ItemView(viewModel: ItemViewModel(shoppingList: selectedShoppingList)) // id变化时SwiftUI会销毁旧实例重建,自动读取最新的选中值 .id(selectedShoppingList.id) })
额外注意
你当前贴出的ItemViewModel代码中未声明shoppingList属性,需要在类中补充对应的属性定义,如果需要在子视图中响应shoppingList的变化,可以给该属性加上@Published包装。
内容的提问来源于stack exchange,提问作者King
相关产品推荐
相关产品推荐

