I am currently switching over to React Hook Form from Formik. I am also using Material UI V5 and yup for validation.
I've got two problems I'm trying to solve at the moment:
- TS Errors are popping up for various RHF props and options.
- I'd like to be able to validate both onBlur and onSubmit, but the HTML5 validation displays onSubmit currently.
Here's my code:
import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import {
Box,
Button,
CircularProgress,
Grid,
InputAdornment,
TextField,
Theme,
Typography,
useMediaQuery,
} from '@mui/material';
import { validationSchema } from './validationSchema'
const LoginForm: React.FC = () => {
const {
control,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
mode: 'onBlur',
reValidateMode: 'onChange',
defaultValues: { // <-- TS Error: Type '{ email: string; password: string; }' is not assignable to type '{ [x: string]: undefined; email?: string | undefined; password?: string | undefined; }'.
email: '',
password: '',
},
});
const handleSignin = async (credentials: Values) => {
const { error } = await signIn(Provider.Email, credentials);
if (error) {
setLoadingLogin(false);
setLoginError(true);
} else {
router.push('/');
}
};
return (
<BoxContainer>
<form onSubmit={handleSubmit(handleSignin)}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Controller
name="email" // <-- TS Error: Type 'string' is not assignable to type 'never'.
control={control}
render={({ field }) => (
<TextField
{...field}
error={!!errors?.email}
helperText={errors?.email?.message} // <-- TS Error: Property 'message' does not exist on type 'never'.
size="small"
autoFocus
label="Email"
fullWidth
autoComplete="email"
type="email"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<EmailIcon />
</InputAdornment>
),
}}
/>
)}
/>
</Grid>
<Grid item xs={12}>
<Controller
name="password" // <-- TS Error: Type 'string' is not assignable to type 'never'.
error={!!errors?.password}
helperText={errors?.password?.message} // <-- TS Error: Property 'message' does not exist on type 'never'.
control={control}
render={({ field }) => (
<TextField
{...field}
size="small"
autoComplete="password"
label="Password"
fullWidth
type="password"
variant="outlined"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<LockIcon />
</InputAdornment>
),
}}
/>
)}
/>
</Grid>
{loginError && (
<Grid item xs={12}>
<Alert severity="error">
There was an error logging in.
<br /> Please try again.
</Alert>
</Grid>
)}
<Grid item xs={12}>
<Button
color="primary"
// disabled={isSubmitting || loadingLogin}
disableElevation
disableRipple
fullWidth
size="large"
type="submit"
variant="contained">
Signin
</Button>
</Grid>
<Grid item xs={12}>
<Typography
variant="body2"
color="textSecondary"
className="text-center">
Don't have an account?{' '}
<Link href="/register">
<a>Signup</a>
</Link>
</Typography>
{!isDesktop && (
<Box marginTop={2}>
<Typography
variant="body1"
color="textSecondary"
className="text-center">
<Link href="/forgot-password">
<a>Forgot your password?</a>
</Link>
</Typography>
</Box>
)}
<Box mt={2} className="text-center">
<Typography
variant="subtitle2"
color="textSecondary"
className="mt-4">
By continuing to use GearCloset, you agree to our{' '}
<Link href="/terms-and-conditions">
<a>Terms and Conditions.</a>
</Link>
</Typography>
</Box>
</Grid>
</Grid>
</form>
</BoxContainer>
);
}
I have commented next to the pieces of code return TS errors.
The second issue is that when I enter an invalid or blank email and then tab, the error state for the input works correctly, however when I press the submit button the email input displays the normal HTML5 validation warning. I'd like for the mode to somehow be both onBlur and onSubmit.
At this point, it seems like RHF works, I'm just cleaning up the errors and functionality.
CodePudding user response:
I think your first issue could be linked to this open Github issue. There is a workaround, check this SO answer.
For the second one you have to set noValidate
attribute on the <form />
element and let RHF completely handle the validation.
<form onSubmit={handleSubmit(handleSignin)} noValidate>