Keep ScrollView position when adding items on the top using onAppear / onScrollTargeVisibilityChange

Related Post: Keep ScrollView position when adding items on the top

I was trying to implement a message view using ScrollView + LazyVStack. This view requires pagination so I used onScrollTargeVisibilityChange modifier to detect if the first item appears on screen and a new page needs to be loaded. I learnt from the above post that scrollPositon modifier can help keep the scroll position. I tested the method mentioned in that post -- use a button to add new items to the top -- and it worked.

However, when use onScrollTargeVisibilityChange modifier to add items, the view automatically scrolls to the top and cause the following loop:

first item in the list appears on screen --> load and insert more items to the top --> scroll view scrolls to top --> first item appears --> load more data --> scroll to top --> first item ... --> more data... --> top ...

Until it generates the error ScrollTargetVisibilityChange tried to update multiple times per frame.

Here is the simplified code.

struct Item: Identifiable {
    var id: UUID = .init()
    var content: String
}

struct ScrollViewTest: View {
    @State private var items: [Item] = (0...30).map {Item(content:"\($0)")}.reversed()
    @State private var itemID: Item.ID?
    @State private var page: Int = 0
    
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(items) {item in
                    Text(item.content)
                        .frame(height: 30)
                }
            }
            .scrollTargetLayout()
        }
        .scrollPosition(id: $itemID)
        .defaultScrollAnchor(.bottom)
        .onScrollTargetVisibilityChange(idType: Item.ID.self) { onScreenItemIDs in
            if onScreenItemIDs.first == items.first?.id {
                page += 1
                let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")}
                items.insert(contentsOf: newItems.reversed(), at: 0)
            }
        }
        .toolbar {
            Button("Add") {
                page += 1
                let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")}
                items.insert(contentsOf: newItems.reversed(), at: 0)
            }
        }
    }
}

I want to load data while scrolling without the need of pressing any buttons. How can I solve this problem?

Keep ScrollView position when adding items on the top using onAppear / onScrollTargeVisibilityChange
 
 
Q