How does a LazyVStack
in SwiftUI decide if it needs to re-render a View, assuming the Identifiable property of an item it is rendering does not change?
This trivial demo code below, I feel, should not update when the button is clicked, because the Identifiable
property of the underlying data set does not change, so no Views should be redrawn and it should use the views it has already cached. However, it seems to work just fine, and I am confused as to why.
struct SomeData: Identifiable {
var id: Int
var name: String
}
struct ContentView: View {
static let dataSetA: [SomeData] = [
.init(id: 1, name: "One A"),
.init(id: 2, name: "Two A"),
.init(id: 3, name: "Three A"),
.init(id: 4, name: "Four A"),
.init(id: 5, name: "Five A"),
.init(id: 6, name: "Six A"),
.init(id: 7, name: "Seven A"),
.init(id: 8, name: "Eight A"),
.init(id: 9, name: "Nine A"),
.init(id: 10, name: "Ten A")
]
static let dataSetB: [SomeData] = [
.init(id: 1, name: "One B"),
.init(id: 2, name: "Two B"),
.init(id: 3, name: "Three B"),
.init(id: 4, name: "Four B"),
.init(id: 5, name: "Five B"),
.init(id: 6, name: "Six B"),
.init(id: 7, name: "Seven B"),
.init(id: 8, name: "Eight B"),
.init(id: 9, name: "Nine B"),
.init(id: 10, name: "Ten B")
]
@State var data: [SomeData] = dataSetA
var body: some View {
LazyVStack {
ForEach(data) { datum in
Text(datum.name)
}
Button("Click") {
data = Self.dataSetB
}
}
.padding()
}
}
Your
@State
variable is not the individual items, but the array enclosing them – and arrays are also a value type. So when you setdata
to be a different array, SwiftUI is (correctly) identifying that the view needs to be reassessed.When it does that reassessment, it doesn't matter that your arrays' constituent items have similar identifiers – the array is different, so the whole list gets re-rendered.