Reputation: 101
I have a SwiftUI
List, which has thousands of items. Each item is as such:
class Item: Codable, Identifiable {
var id = UUID()
var prop1 = ""
var prop2 = ""
}
Now I do this:
List(store.items.indices, id: \.self) { index in
DetailView(item: self.$store.items[index])
}.id(UUID())
I iterate the indicies
because I have to pass a Binding
to the DetailView
.
Now the DetailView
has TextFields
attached to the Item
's properties.
When DetailView
changes an Item
's properties, it causes the List
to refresh ALL of the items, which I dont want.
Also, it's still important that when one of those properties changes, the main view is updated, because on macOS, the main view is still visible even when you click on one of the items.
My question is how to make it so that whenever an Item
passed in from the List
changes, only update that row?
I also tried a solution mentioned where I use a LazyVStack
, and it fixes the performance issue, but I use the List
inside of a NavigationView
, and the LazyVStack
doesn't seem to support that.
Any suggestions are greatly appreciated.
Upvotes: 5
Views: 1012
Reputation: 9915
You could use a LazyVStack
in a ScrollView
as long as you don't need List
specific functionality. List
s aren't as efficient as LazyVStack
s yet (Apple bug).
ScrollView {
LazyVStack {
ForEach(store.items.indices) { index in
DetailView(item: self.$store.items[index])
}
}
}
Upvotes: 1
Reputation: 5105
Remove .id(UUID())
from the List.
By default, List diffs changes and only updates the affected rows. For very large data sets, that .id(UUID())
trick is used to force the whole List to reload when something changes, which may be faster than trying to diff the large dataset. It doesn’t sound like you need it, so it’s actually worse to include it unnecessarily.
Edit: I don’t think binding to the array by index is the problem, but it is unusual and may bite you eventually.
Upvotes: 4