Home > Software design >  Wire SwiftUI Interaction among Components
Wire SwiftUI Interaction among Components

Time:03-30

I am trying to wire up two 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)
}

So, a person enters their email address and as they type, the emailAddressChangedValue emits the typed text. The email address is validated through validateEmail(emailAddress: emailAddressChangedValue) and once a valid email address occurs, the button becomes enabled. However, I cannot figure out how to change the $buttonState which changes the color style from disabled to enabled. I tried putting it within the validateEmail function but when I do that, I receive an error Modifying state during view update, this will cause undefined behavior.

So, how do I update buttonState within the VStack?

CodePudding user response:

Assuming TextEdit is like TextField or TextEditor, you could try adding .onReceive{}, like the following example code, to "...update buttonState within the VStack." (note, you need to 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)
}
  • Related