.keyboardShortcut on Button in Swift doesn't properly rerender unless button.label changes

here is minimal reproducible example:

import SwiftUI

struct ContentView: View {
  @State var options = ["1","2","3","4"]
  @State var option = "1"

  var body: some View {
    ForEach(options, id: \.self) { item in
      Button(item, action: {
        self.option = item
      })
    }

    ChildView(model: .init(option: option))
  }
}

class ChildViewModel: ObservableObject {
  @Published var option: String
  init(option: String) {
    self.option = option
  }
}

struct ChildView: View {
  @ObservedObject var model: ChildViewModel

  var body: some View {
    Text(model.option)

    Button("Tab", action: {
      print("Option: \(model.option)")
    })
    .keyboardShortcut("f")
  }
}


struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

Here is steps to reproduce:

  1. click "2" item
  2. click "Tab" Button, which will prints "Option: 2"
  3. press Cmd+F, which will prints "Option: 1"

step(3) is unexpected behavior, since it has to print "Option: 2"

If you change Button("Tab") into Button("Tab (model.option)"), step 3 will produce proper result of printing "Option: 2"

So i assume this is issue of keyboardShortcut not properly referencing "latest" action - unless "label" of button changes, keyboardShortcut does not use latest "action" that is given. but as you can see from example, clicking button will result calling latest action

I get the same effect.

However, the shortcut works only once, then I have to change to another shortcut for it to work again (and once only).

Maybe that is a simulator issue ? see discussion here: https://stackoverflow.com/questions/66356450/swiftui-keyboard-shortcut-doesnt-work-if-button-has-a-buttonstyle

Actually, i've been doing this on macOS target. (without mac catalyst) so no simulator.
i don't think it's button style issue either, the example i shared is 100% reproducible, regardless of button style.
it's just that .keyboardShortcut is keep calling "outdated" action, that already been replaced by button.
also, as i wrote on original post, it works perfectly fine if i force rerender of button by changing label to use model.option

I am noticing the same issue. Did you find any solution?

I was running into this and found that setting the localization parameter to something other than ".automatic" fixed it. For example, .keyboardShortcut("r", modifiers: [.command], localization: .withoutMirroring)

.keyboardShortcut on Button in Swift doesn't properly rerender unless button.label changes
 
 
Q