连接组件之间的 SwiftUI 交互

Wire SwiftUI Interaction among Components

我正在尝试连接两个组件:

@State private var buttonState = ButtonState.DISABLED
@State private var emailAddressChangedValue = ""

VStack {
    TextEdit(editText: $viewModel.email, changedValue: $emailAddressChangedValue, placeholder: NSLocalizedString("onboarding.forgotpassword.email.label", comment: ""), keyboardType: UIKeyboardType.emailAddress)
            .padding(.top, 4)

    Button(action: {
        viewModel.sendPasswordResetRequest()
    }, label: {
            Text(NSLocalizedString("onboarding.forgotpassword.sendemail.label", comment:""))
            .padding()
            .font(.headline)
            .foregroundColor(Color.white)
    })
    .buttonStyle(FooButtonStyle(buttonState: $buttonState))
    .disabled(!validateEmail(emailAddress: emailAddressChangedValue))
    .padding(.top, 8)
    .padding(.horizontal, 8)
}

因此,一个人输入他们的电子邮件地址,并在他们键入时,emailAddressChangedValue 发出键入的文本。电子邮件地址通过 validateEmail(emailAddress: emailAddressChangedValue) 验证,一旦出现有效的电子邮件地址,该按钮就会启用。但是,我不知道如何更改 $buttonState 将颜色样式从禁用更改为启用。我尝试将它放在 validateEmail 函数中,但是当我这样做时,我收到错误消息 Modifying state during view update, this will cause undefined behavior.

那么,如何在 VStack 中更新 buttonState

假设 TextEdit 类似于 TextFieldTextEditor,您可以尝试将 .onReceive{} 添加到“...在堆栈。” (注意,你需要import Combine):

VStack {
    TextEdit(editText: $viewModel.email, changedValue: $emailAddressChangedValue, placeholder: NSLocalizedString("onboarding.forgotpassword.email.label", comment: ""), keyboardType: UIKeyboardType.emailAddress)
        .padding(.top, 4)
    
    Button(action: {
        viewModel.sendPasswordResetRequest()
    }, label: {
        Text(NSLocalizedString("onboarding.forgotpassword.sendemail.label", comment:""))
            .padding()
            .font(.headline)
            .foregroundColor(Color.red)
    })
    // -- here --
    .onReceive(Just(emailAddressChangedValue)) { val in
       buttonState = !validateEmail(emailAddress: val)
    }
    .buttonStyle(FooButtonStyle(buttonState: $buttonState))
    .disabled(buttonState) // <-- could also be here 
    .padding(.top, 8)
    .padding(.horizontal, 8)
}