react-hook-form handling server-side errors in handleSubmit
In order to display the error from the server to your user, you need to use:
setError
to set the error programmatically when the server returns an error response.errors
to get the error state of every fields in your form to display to the user.
type FormInputs = { username: string;};const { setError, formState: { errors } } = useForm<FormInputs>();
In your handleSubmit
callback
axios .post(url, data) .then((response) => { alert("Login successful"); }) .catch((e) => { const errors = e.response.data; if (errors.username) { setError('username', { type: "server", message: 'Something went wrong with username', }); } if (errors.password) { setError('password', { type: "server", message: 'Something went wrong with password', }); } });
In your component
<label htmlFor="username">username</label><input id="username" {...register("username")} /><div>{errors.username && errors.username.message}</div>
Live Demo
Inspired by @NearHuscarl's answer, I've done the following hack s.t. changes in either the username
or the password
inputs will remove the single error.
This hack does not scale well if your error is related to multiple fields in the form, but it worked for the login use case.
onSubmit:
const onSubmit = handleSubmit(async (data) => { const url = '/auth/local' const [err, userLoginResult] = await to<AxiosResponse>(axios.post(url, data)) // see await-to-js if (userLoginResult) { alert('Login successful') } else if (err) { const formError = { type: "server", message: "Username or Password Incorrect" } // set same error in both: setError('password', formError) setError('username', formError) } })
component:
return ( <div className="RegisterOrLogIn"> <form onSubmit={onSubmit}> <div> <label htmlFor="username">username</label> <input name="username" id="username" ref={register} /> </div> <div> <label htmlFor="password">Password</label> <input type="password" id="password" name="password" ref={register} /> </div> <div>{errors.username && errors.password?.message /*note the cross check*/}</div> <button type="submit"> </button> </form> </div> )
by setting and rendering the error on both errors.password
& errors.username
, the error will disappear when the user updates either of those fields.