Reputation: 71
How can I make sure that handleOpen
only executes after all the states (nameError
, emailError
, messageError
) have been updated? My problem is that since state doesn't update immediately, sometimes handleOpen
executes when it shouldn't.
const handleSend = (e) => {
e.preventDefault();
if (name === "") {
setNameError(true);
}
if (email === "") {
setEmailError(true);
setEmailErrorMessage("Please type your email!");
}
if (!email.includes("@")) {
setEmailError(true);
setEmailErrorMessage("Invalid email address");
}
if (message === "") {
setMessageError(true);
}
if (!nameError && !emailError && !messageError) {
handleOpen();
}
};
Upvotes: 3
Views: 201
Reputation: 240
The best scenario you could follow for these kinds of problems is that you create another state or even a constant that has the checks for the validation and then put it in the useEffect to check if the value is changed and then whenever it is changed, you check it if it holds true or no. for better understanding you can do like this:
const [wholeValidate, setWholeValidate] = useState(false);
const handleSend = (e) => {
e.preventDefault();
if (name === "") {
setNameError(true);
}
if (email === "") {
setEmailError(true);
setEmailErrorMessage("Please type your email!");
}
if (!email.includes("@")) {
setEmailError(true);
setEmailErrorMessage("Invalid email address");
}
if (message === "") {
setMessageError(true);
}
if (!nameError && !emailError && !messageError) {
setWholeValidate(true);
}
useEffect(() => {
if(wholeValidate) {handleOpen();}
}, [wholeValidate])
Upvotes: 0
Reputation: 3968
I see that you are struggling with JS Event Loop. React states will update after an event loop is finished. So you can't expect them to update immediately in your handler function.
However there are some other solutions like using setTimeout(..., 0) to cheat the event loop, which is not going to help you in this case.
Here you need to refactor the handler method to handle the error states in your function scope and set the final result to the error states.
const handleSend = (e) => {
e.preventDefault();
const errors = {
name: '',
email: '',
message: '',
};
if (name === "") {
errors.name = "Please enter your name";
}
if (email === "") {
errors.email = "Please type your email!";
}
if (!email.includes("@")) {
errors.email = "Invalid email address";
}
if (message === "") {
errors.email = "Please enter a message";
}
setNameError(!!errors.name);
setNameErrorMessage(errors.name);
setEmailError(!!errors.email);
setEmailErrorMessage(errors.email);
setMessageError(!!errors.message);
setMessageErrorMessage(errors.message);
if (Object.values(errors).filter(Boolean).length === 0) {
handleOpen();
}
}
I strongly suggest refactoring the error handling process in your application. Your solution and the one I wrote here is not efficient at all.
Good Luck ;)
Upvotes: 1
Reputation: 604
I would do a whole refactor on how you are handling the errors, but answering your question, you could do just this:
const handleSend = (e) => {
e.preventDefault();
const isNameEmpty = name === "";
const isEmailEmpty = email === "";
const isEmailAtMissing = !email.includes("@");
const isMessageEmpty = message === "";
setNameError(isNameEmpty);
setEmailError(isEmailEmpty || isEmailAtMissing);
setEmailErrorMessage(isEmailEmpty ? "Please type your email!" : "Invalid email address");
setMessageError(isMessageEmpty);
if ([isNameEmpty, emailError, emailError].some(value => !!value)) {
handleOpen()
}
}
If you save the "errors" in variables, then you make sure you are checking the last values you are using in the states.
Upvotes: 0
Reputation: 2150
You can use react's useRef
hook, for its not reactive, i.e doesnt cause page rerender so that you're sure
if (!nameError && !emailError && !messageError) {
handleOpen();
}
executes when the right in the order you wanted just as i'll show below
const setNameError = useRef(null);
const setEmailError = useRef({value : false, message : ''});
const setMessageError = useRef(null);
const handleSend = (e) => {
e.preventDefault();
if (name === "") {
setNameError.current = true;
}
if (email === "") {
setEmailError.current.value = true;
setEmailError.current.message = "Please type your email!";
}
if (!email.includes("@")) {
setEmailError.current.value = true;
setEmailError.current.message = "Invalid email address";
}
if (message === "") {
setMessageError.current = true;
}
if (!setNameError.current && !setRmailError.current && !setMessageError.current) {
handleOpen();
}
};
i have used bad naming conversion so as to go with your example, but in real life you wont chose setNameError
for a variable name as I've done but maybe you'll do nameError
Upvotes: 0