See Update Below
I have a Login Form Component that I built using Formik that syncs with Firebase Authentication. I have set it up so that I can display errors from Firebase using the setFieldError
prop. Here is the relevant sections of the code:
export const LoginForm = () => {
async function authenticateUser(values, setFieldError) {
const { email, password } = values
try {
await firebase.login(email, password)
navigate('/', { replace: true })
} catch (error) {
console.log('Authentication Error: ', error)
await setFieldError('firebaseErrorMessage', error.message)
}
}
return (
<>
<h1>Form</h1>
<Formik
render={props => <RenderForm {...props} />}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (
values,
{ setFieldError, setSubmitting, resetForm }
) => {
setSubmitting(true)
authenticateUser(values, setFieldError)
setSubmitting(false)
resetForm()
}}
/>
</>
)
}
const RenderForm = ({ errors, isSubmitting, isValid }) => (
<Form>
<h3>Sign Up</h3>
<Email name="email" />
<Password name="password" />
<Button disabled={!isValid || isSubmitting} type="submit">
Submit
</Button>
{errors.firebaseErrorMessage && <p>{errors.firebaseErrorMessage}</p>}
</Form>
)
Now, this works just fine. However, if I try to display the error message using Formik's ErrorMessage
component, then the message does not show up.
In other words, this works:
{errors.firebaseErrorMessage && <p>{errors.firebaseErrorMessage}</p>}
This does not work:
<ErrorMessage name="firebaseErrorMessage" />
Any idea why this doesn't work and how to get it to work?
Thanks.
UPDATE
Here are my initial values:
const initialValues = {
email: '',
password: '',
}
I don't think that you should use Formik's error for your Firebase error. Formik's errors are meant for validating form inputs.
To store and reference an API error, you can use Formik's status
object. Handling API errors is the example he gives for status
.
I think the issue is that, in Formik, name
is meant to refer to the name of an input. Instead, you're imperatively adding a new name property to the errors
object using setFieldError
, but firebaseErrorMessage
isn't a field in your form. (Share your initialValues
object to verify this.)
One annoying part of this is that there is probably some styling associated with <ErrorMessage>
that you can't leverage directly. But, in my opinion, it's probably more important to have your system structured correctly, and then you can mimic styles as-needed.
Here's my code suggestion:
const RenderForm = ({ isSubmitting, isValid, status }) => (
<Form>
<h3>Sign Up</h3>
<Email name="email" />
<Password name="password" />
<Button disabled={!isValid || isSubmitting} type="submit">
Submit
</Button>
{status.firebaseErrorMessage && <p>{status.firebaseErrorMessage}</p>}
</Form>
);
export const LoginForm = () => {
async function authenticateUser(values, setStatus, setSubmitting) {
const { email, password } = values;
setSubmitting(true);
try {
await firebase.login(email, password);
navigate("/", { replace: true });
} catch (error) {
console.log("Authentication Error: ", error);
setStatus({
firebaseErrorMessage: error.message
});
} finally {
setSubmitting(false);
}
}
return (
<>
<h1>Form</h1>
<Formik
render={props => <RenderForm {...props} />}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (values, { setStatus, setSubmitting, resetForm }) => {
await authenticateUser(values, setStatus, setSubmitting);
resetForm();
}}
/>
</>
);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With