Reputation: 2807
I'm using Formik in my Next.js app, and i ran into a problem that I'm not sure how to fix. My submit Button
is a component that accepts a showSpinner
prop. If it is true -> button is disabled and a loading spinner in a button is displayed. showSpinner
value depends on loading
that is coming from useState
hook. Here is a relevant code:
export default function register() {
const [loading, setLoading] = useState(false)
return (
<>
<Layout>
<div className={styles.registerContainer}>
<div className={styles.registerFormContainer}>
<h1 className={styles.registerHeader}>Sign Up</h1>
<Formik
initialValues={{
email: '',
password: '',
passwordConfirm: '',
acceptedTerms: false
}}
onSubmit={
(values, { setSubmitting }) => {
console.log(loading)
// here loading == false as expected
setLoading(true)
console.log(loading)
// here loading == false even though i set it to true
initFirebase()
firebase.auth().createUserWithEmailAndPassword(values.email, values.password)
.then((res) => {
console.log('done!')
})
.catch(function (error) {
// Handle Errors here.
console.log(error)
})
.finally(() => {
console.log(loading)
//here loading == false too, even though I expected it to be true
setSubmitting(false)
setLoading(false)
})
}
}
>
<Form>
<FormikText label="Email:"
name="email"
type="email"
id="email" />
<FormikPassword label="Password:"
name="password"
id="password"
/>
<FormikPassword label="Confirm Password:"
name="passwordConfirm"
id="passwordCOnfirm"
/>
<FormikCheckbox
name="acceptedTerms"
id="acceptedTerms"
>
<span className={styles.checkboxLabel}>
I agree to the <Link href="/terms" ><a className={styles.registerLink}>Terms of Service</a></Link> and <Link href="/privacy"><a className={styles.registerLink}>Privacy/Cookie Policy</a></Link>
</span>
</FormikCheckbox>
<div className={styles.buttonContainer}>
<Button type="submit" color="blue" showSpinner={loading}>Sign Up</Button>
</div>
</Form>
</Formik>
</div>
</div>
</Layout>
</>
)
}
Even though my Button
is somehow working as expected (spinner is displayed as intended), after console.loging
value of loading
through onSubmit
function call I noticed that it is false
were I expected it to be true. Is it due to the way React batches useState
calls?
My questions are:
loading == false
in those console.logs
, why is my Button
working as intended ?Upvotes: 2
Views: 4541
Reputation: 20805
is it due to the way React batches useState calls?
I think so, that's precisely why Formik
provides a isSubmitting
flag, try using it instead of tracking your own loading
state, I know it's working for your current specs but you could have some issues when this component gets more complex
Your code would look like this
export default function register() {
return (
<>
<Layout>
<div className={styles.registerContainer}>
<div className={styles.registerFormContainer}>
<h1 className={styles.registerHeader}>Sign Up</h1>
<Formik
initialValues={{
email: "",
password: "",
passwordConfirm: "",
acceptedTerms: false,
}}
onSubmit={async (values) => {
try {
initFirebase();
await firebase
.auth()
.createUserWithEmailAndPassword(
values.email,
values.password
);
} catch (e) {
// Handle Errors here.
console.log(error);
}
}}
>
{({ isSubmitting }) => (
<Form>
<FormikText
label="Email:"
name="email"
type="email"
id="email"
/>
<FormikPassword
label="Password:"
name="password"
id="password"
/>
<FormikPassword
label="Confirm Password:"
name="passwordConfirm"
id="passwordCOnfirm"
/>
<FormikCheckbox name="acceptedTerms" id="acceptedTerms">
<span className={styles.checkboxLabel}>
I agree to the{" "}
<Link href="/terms">
<a className={styles.registerLink}>Terms of Service</a>
</Link>{" "}
and{" "}
<Link href="/privacy">
<a className={styles.registerLink}>
Privacy/Cookie Policy
</a>
</Link>
</span>
</FormikCheckbox>
<div className={styles.buttonContainer}>
<Button
type="submit"
color="blue"
showSpinner={isSubmitting}
>
Sign Up
</Button>
</div>
</Form>
)}
</Formik>
</div>
</div>
</Layout>
</>
);
}
taken from here https://formik.org/docs/examples/async-submission
Upvotes: 1