Home > Back-end >  React Hook Form - Typescript issues and error handling?
React Hook Form - Typescript issues and error handling?

Time:09-30

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:

  1. TS Errors are popping up for various RHF props and options.
  2. 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>
  • Related