On a ScrollView+LazyVStack, the addition of .scrollTargetLayout causes many list items to be initialized, instead of the ordinary economical behavior of LazyVStack, where only the necessary items and views are initialized. Even worse, as the stack is scrolled down, all list items are reinitialized for every small scroll.
Without, .scrollTargetLayout, everything works fine.
I've tried every variation of locating modifiers, and different ways of identifying the list items, with no success.
Any ideas? Thanks.
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Post.created, ascending: true)],
animation: .default)
private var posts: FetchedResults<Post>
var body: some View {
ZStack{
ScrollView{
LazyVStack(spacing:0) {
ForEach(posts, id: \.self) { post in
PostView(post: post)
}
.onDelete(perform: deletePosts)
}.scrollTargetLayout() // <---- causes multiple Posts re-instantiations for any small scroll, very slow
}
.scrollPosition(id: $scrolledID)
.scrollTargetBehavior(.paging)
Found the cause and fix, though I don't 100% understand why it's happening. The views in the VStack (PostView in the code above) contained a @SceneStorage property. Removing the @SceneStorage allows the list to scroll quickly, even with .scrollTargetLayout(). No excessive calls to .body.
I'm guessing that as the scrolled views come and go, that the @SceneStorarge var was getting marked as changed, even though it wasn't, causing all other cached views to be invalidated? But how does .scrollTargetLayout cause this?
Anyway, elevating the @SceneStorage to the containing view, and passing into PostView as a binding, fixed scrolling, and still gives access to that @ScensStorage var.