HowTo - SwiftUI 2.0 LazyVStack and LazyHStack

Published on

Get weekly handpicked updates on Swift and SwiftUI!

SwiftUI 2.0 introduces LazyVStack and LazyHStack, which only render Views when they are within the visible area. This significantly improves app performance. The efficiency issues caused by VStack or HStack have been briefly compared in the article SwiftUI List (3) - List, Form, VStack.

Basic Usage

Swift
struct LazyStack: View {
    var body: some View {
        ScrollView{
            LazyVStack{ // Replace with VStack for a comparison of when new data is created
                ForEach(0...1000, id: \.self){ id in
                    Text(LazyItem(id: id).title)
                }
            }
        }
    }
}

struct LazyItem{
    let id: Int
    let title: String
    init(id: Int){
        self.id = id
        self.title = "id: \(id)"
        print("init new object: \(id)") 
    }
}

Using Lazy Feature to Create Continuous List Display

Swift
import SwiftUI

struct LazyStack: View {
    @State var list = (0...40).map{ _ in Item(number: Int.random(in: 1000...5000)) }
    @State var loading = false
    var body: some View {
        VStack{
            Text("count: \(list.count)")
            // Data count. Under LazyVStack, data increases each refresh. Under VStack, data continuously increases.
            ScrollView{
                LazyVStack{ // Replace with VStack for comparison
                    ForEach(list, id: \.id){ item in
                        Text("id: \(item.number)")
                            .onAppear {
                                moreItem(id: item.id)
                            }
                    }
                }
                if loading {
                    ProgressView()
                }
            }
        }
    }
    
    func moreItem(id: UUID){
        // If it's the last data, then fetch new data
        if id == list.last!.id && !loading {
            loading = true
            // Add delay to simulate asynchronous data fetching
            DispatchQueue.main.asyncAfter(deadline: .now() + 1){
                // Data simulation, can also fetch from the network
                list.append(contentsOf: (0...30).map{ _ in Item(number: Int.random(in: 1000...5000)) })
                loading = false
            }
        }
    }
}

struct Item: Identifiable{
    let id = UUID()
    let number: Int
}

The usage of LazyHStack is similar to LazyVStack.

Weekly Swift & SwiftUI insights, delivered every Monday night. Join developers worldwide.
Easy unsubscribe, zero spam guaranteed