Sheet presented through a ContextMenu is missing it's data on the first try

Viewed 82

I'm having an issue presenting a Sheet when selecting one of the options in a ContextMenu. The first time that the Sheet is presented, it's missing the initial data. Following presentations work just fine, it's just the first one that presents the wrong behavior. Has anyone seen anything similar? I'm wondering if it's just a bug or I'm doing something wrong.

Sample code to demonstrate the issue:

struct ContentView: View {
    
    var options =  ["One", "Two", "Three"]
    
    @State var modalText: String?
    @State var isShowingModal = false
    
    var body: some View {
        List(options, id: \.self) { option in
            Text(option).contextMenu {
                Button("Edit") {
                    // Store the option that we want to modify
                    modalText = option
                    // Trigger the modal
                    isShowingModal = true
                }
            }
        }.toolbar {
            Button {
                // Trigger the modal with no previous data because it's creation
                isShowingModal = true
            } label: {
                Text("Create")
            }
        }.sheet(isPresented: $isShowingModal) {
            // Reset the state, the modal might be used to edit or create
            // (create doesn't pass an initial value)
            modalText = nil
        } content: {
            Text("Edit or Create modal for \(modalText ?? "NOTHING")")
        }
    }
}

Video demonstrating the issue: https://twitter.com/xmollv/status/1413028616112414721

2 Answers

I don't really understand why your code does not work. But you could try this to make it work:

class ModalText: ObservableObject {
    @Published var text: String?
}

struct ContentView: View {
    var options =  ["One", "Two", "Three"]
    
    @StateObject var modalText = ModalText()
    @State var isShowingModal = false
    
    var body: some View {
        List(options, id: \.self) { option in
            Text(option).contextMenu {
                Button("Edit") {
                    modalText.text = option
                    isShowingModal = true
                }
            }
        }
        .toolbar {
            Button {
                // Trigger the modal with no previous data because it's creation
                isShowingModal = true
            } label: {
                Text("Create")
            }
        }
        .sheet(isPresented: $isShowingModal) {
            // Reset the state, the modal might be used to edit or create
            // (create doesn't pass an initial value)
            modalText.text = nil
        } content: {
            Text("Edit or Create modal for \(modalText.text ?? "NOTHING")")
        }
    }
}

Use selection parameter and it will work:

List(options,id: \.self, selection: $modalText) { option in
    Text(option).contextMenu {
        Button("Edit") {
            // Store the option that we want to modify
            modalText = option
            // Trigger the modal
            isShowingModal = true
        }
    }
}
Related