【发布时间】:2021-09-26 13:02:51
【问题描述】:
struct ContentView: View {
@State var items = ["red", "blue", "green"]
var body: some View {
VStack {
ForEach(items.indices, id: \.self) { idx in
ItemView(str: items[idx])
}
Button("Replace items") {
items = [ "pig", "dog", "horse" ]
}
}.frame(width: 200, height: 150)
}
}
struct ItemView: View {
@State var itemstr = ""
let str: String
var body: some View {
HStack {
Text(str)
TextField("New: "+str, text: $itemstr)
}
}
}
输入一些文字。
现在按下“替换项目”按钮。
现在你可以看到 TextField @State 和“str”标签数据不一致。 “pig”来自刷新后的视图,“rreedd”来自旧的视图副本。
确认文本初始值也不一致。
看起来 ItemView 自定义视图正在使用新的初始化参数 (str) 但使用旧状态 (itemstr) 进行重构。
我真正的问题比这更复杂。但它涉及使用 ForEach 创建的子视图,并且当模型数据发生更改时,ForEach 不会按照我期望的方式重新迭代。
我不确定这是否是 SwiftUI 错误,因为我不深入了解 SwiftUI 用于传播视图更改的算法。
好像它创建了一个新视图,将新视图的内部状态与旧视图的内部状态进行比较,然后决定是重新计算子视图并使用新视图还是坚持旧视图。但我从未在官方文档中看到过这样的说明。
【问题讨论】:
-
也许在
ItemView中使用@Binding而不是@State? -
@aheze,你可以直接绑定,但是这种方法通常用于子视图想要保持其“未保存”状态而不直接更新父视图的情况
-
@NewDev 啊,我明白了,很好的答案!