To make the user experience more intuitive, let's disable the Register button until both the email and password fields are valid. To do that, we need to provide a way for the RegistrationForm component to not just read the values of the Input components when the form is submitted, but after each time the value has changed.
A naive approach would be to poll the valid state of each component every 100 ms or so, but that will not be performant. Instead, we can pass a function (via the onChange prop) into the Input component that will get called whenever the value of the Input changes.
<Input label="Email" type="email" ref={this.email} onChange={this.handleInputChange} />
<Input label="Password" type="password" ref={this.password} onChange={this.handleInputChange} />
And then inside the validate method of our Input component, we would call this.props.onChange:
validate = (event) => {
const value = event.target.value;
const valid = validator[this.props.type](value);
this.setState({ value, valid }, () => {
if (this.props.onChange) {
this.props.onChange();
}
});
}
The setState method accepts a callback as its second parameter, which only gets called after the state has been updated. This ensures that when the parent component (RegistrationForm) checks the Input elements' states, it will be the updated state.
Now, we need to define the handleInputChange method in RegistrationForm. It should check whether both inputs are valid, and store the result in the state of RegistrationForm.
constructor(props) {
super(props);
this.email = React.createRef();
this.password = React.createRef();
this.state = {
valid: false
};
}
...
handleInputChange = () => {
this.setState({
valid: !!(this.email.current.state.valid && this.password.current.state.valid)
})
}
Finally, we need to modify our Button component to accept a disabled prop, which should disable the button when true.
function Button(props) {
return <button disabled={props.disabled}>{props.title}</button>
}
class RegistrationForm extends React.Component {
...
render() {
return (
<form onSubmit={this.handleRegistration}>
...
<Button title="Register" disabled={!this.state.valid} />
</form>
)
}
}
Now, refresh the page and play around with the inputs. The Register button should now be disabled until both inputs are valid (that is, both indicators are green).