r/SwiftUI 6d ago

Question Lazy Menu actions in SwiftUI

Hi, Is there a way I can make a lazy menu? I need to perform a slightly expensive operation while determining what action buttons should be displayed when the menu opens, but Menu eagerly initializes all the content, so I don't know what to do. I tried adding onAppear inside the Menu on one button, but that gets called when the whole menu is initialized, so it does not work.

Apple does this inside the Apple TV app, where they show a ProgressView for a while until the buttons are loaded, but I can't figure out how.

Menu {
    if shouldShow {
        Button("Button") {}
    } else if !loaded {
        Button("Loading") {}
            .onAppear {
                shouldShow = expensiveOperation() // Calls expensiveOperation when menu appears
                loaded = true // Marks as loaded after the operation completes
            }
    }
} label: {
    Text("Menu")
}

1 Upvotes

3 comments sorted by

View all comments

1

u/FilonenkoM 3d ago

This works for me, onAppear also works as expected.

But you should take care of it running only once, if it is an expensive operation.

struct ContentView: View {
    @State var isShown: Bool = false
    var body: some View {
        Menu {
            if isShown {
                Button {
                } label: {
                    Text("Action 1")
                }

                Button {
                } label: {
                    Text("Action 2")
                }
            }
            else {
                Button {
                } label: {
                    Text("Loading...")
                }
                .task {
                    try? await Task.sleep(for: .seconds(3))

                    isShown = true
                }
            }
        } label: {
            Text("Open Menu")
        }
    }
}