Reputation: 1081
I have a registration form. When I click the Register button all TextInputs
are validated and for each field I call a function in which I call e.g. this.setState({usernameError: 'This field is required'})
.
So for each text field I have a function to set the error state for this field. After I press the Register button I want to validate all fields and then return the function if there is any field error in the state (The user may not register if all fields have not been filled in correctly). The problem is: Because setState
is asynchronous, it is not guaranteed that all field errors are already correctly set when I check them.
2 important annotations:
validate<FieldName>
functions in other places, e.g. when the onChangeText
event occurs)So my question is: How to make sure the state is already updated when checking its values without giving up my reusable "validator functions"?
Some code to make it clearer:
state = { usernameError: '', firstNameError: '', lastNameError: '' };
setUsernameError = () => { // This function is also called elsewhere than in handlePressRegister
const { username } = this.state;
if (username === '')
this.setState({ usernameError: 'Required field' });
else if (username.length < 2)
this.setState({ usernameError: 'Minimum 2 characters' });
else
this.setState({ usernameError: undefined });
}
setFirstNameError = () => { // This function is also called elsewhere than in handlePressRegister
...shortened for brevity...
}
setLastNameError = () => { // This function is also called elsewhere than in handlePressRegister
...shortened for brevity...
}
handlePressRegister = () => {
const { usernameError, firstNameError, lastNameError } = this.state;
this.setUsernameError();
this.setFirstNameError();
this.setLastNameError();
if (usernameError || firstNameError || lastNameError) // The errors may not be set in the state yet
return;
I hope you understand my question correctly.
Upvotes: 1
Views: 274
Reputation: 85132
I would handle this by having the various set[X]Error
functions return their new value. For example:
setUsernameError = () => {
const { username } = this.state;
let error = undefined;
if (username === '')
error = 'Required field';
else if (username.length < 2)
error = 'Minimum 2 characters';
this.setState({ usernameError: error });
return error;
}
handlePressRegister = () => {
const usernameError = this.setUsernameError();
const firstNameError = this.setFirstNameError();
const lastNameError = this.setLastNameError();
if (usernameError || firstNameError || lastNameError) {
return;
}
// ...
}
Upvotes: 1
Reputation: 371049
If you promisify setState
, you could return it from each validator call and call Promise.all
on it:
setUsernameError = () => { // This function is also called elsewhere than in handlePressRegister
const { username } = this.state;
if (username === '')
return setStatePromisified({ usernameError: 'Required field' });
// ...
Promise.all([
this.setUsernameError(),
this.setFirstNameError(),
this.setLastNameError(),
])
.then(() => {
// state will be updated now
const { usernameError, firstNameError, lastNameError } = this.state;
if (usernameError || firstNameError || lastNameError) {
return;
}
// submit?
});
Another option would be to add another property into state, say, validating
, that gets set when the register button is pressed. The next render, detect its change in a componentDidUpdate
, reset validating
, and continue with the logic as needed (submit the form if no errors?).
Upvotes: 1