@small magnet My go-to approach for this is to have 2 extra pieces of state - error and emptyFields. The error state displays any error messages from the validation, and the emptyFields state keeps track of any empty required fields.
https://scrimba.com/scrim/c4WE3gcp
Here's a quick and dirty example of this in action. When the user clicks the "submit form" button, the formSubmit function checks to see if the name and email fields are empty. If they are, they pass a string into the emptyFields state, which in turn gives the relevant inputs an "invalid" class, turning their borders red. This also sets the error message and displays it on the screen.
You can add as many different types of validation checks as you like to this, including things like checking for a valid email address, comparing fields, etc and display any error messages you like to the user.