React Hook Form 中所需的属性不会在文本字段上进行验证。

huangapple go评论69阅读模式
英文:

Required property from React hook form does not validate on textfields

问题

以下是您的翻译代码部分:

我目前正在使用React-hook-form来管理我的文本字段以及验证当前的问题是required属性不起作用因为当输入为空时它不会显示小的帮助文本这里是界面的一部分示例它只显示了一些输入字段以节省不必要的JSX代码

这是我如何做的

```javascript
import { FragmentType, useFragment } from '@gql/fragment-masking';
import { graphql } from '@gql/gql';
import { Gender } from '@gql/graphql';
import {
  Button,
  Card,
  CardContent,
  Grid,
  MenuItem,
  TextField,
  TextFieldProps,
  Typography,
} from '@mui/material';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import dayjs, { Dayjs } from 'dayjs';
import { useTranslation } from 'next-i18next';
import React, { useCallback, useState } from 'react';
import { useForm } from 'react-hook-form';

type Inputs = {
  firstName: string;
  lastName: string;
  birthdate: string;
  street: string;
  postalcode: string;
  city: string;
  country: string;
  gender: string;
  email: string;
  leveloftrust: string;
  lastsignedin: string;
};

export const PatientInfoFragment = graphql(/* GraphQL */ `
  fragment PatientInfo on Patient {
    addresses {
      city
      lines
      postalCode
    }
    birthDate
    email
    gender
    id
    name {
      firstName
      lastName
    }
    status {
      lastSignInAt
      levelOfTrust
    }
  }
`);

interface PatientInfoProps {
  patient: FragmentType<typeof PatientInfoFragment>;
}

export function PatientInfo(props: PatientInfoProps) {
  // ...(其余代码)

}

希望这有助于您的需求。如果有任何问题,请随时告诉我。

英文:

I'm currently using React-hook-form to manage my textfields and that includes validation.
The problem right now is that the required property does not work well, because it does not show the little helpertext under the inputfield when it is empty.
Here is there a snippet of the UI, it only shows a few of the inputfields to save you the
unnecessary JSX code
React Hook Form 中所需的属性不会在文本字段上进行验证。

This is how i have done it:

import { FragmentType, useFragment } from &#39;@gql/fragment-masking&#39;;
import { graphql } from &#39;@gql/gql&#39;;
import { Gender } from &#39;@gql/graphql&#39;;
import {
Button,
Card,
CardContent,
Grid,
MenuItem,
TextField,
TextFieldProps,
Typography,
} from &#39;@mui/material&#39;;
import { AdapterDayjs } from &#39;@mui/x-date-pickers/AdapterDayjs&#39;;
import { DesktopDatePicker } from &#39;@mui/x-date-pickers/DesktopDatePicker&#39;;
import { LocalizationProvider } from &#39;@mui/x-date-pickers/LocalizationProvider&#39;;
import dayjs, { Dayjs } from &#39;dayjs&#39;;
import { useTranslation } from &#39;next-i18next&#39;;
import React, { useCallback, useState } from &#39;react&#39;;
import { useForm } from &#39;react-hook-form&#39;;
type Inputs = {
firstName: string;
lastName: string;
birthdate: string;
street: string;
postalcode: string;
city: string;
country: string;
gender: string;
email: string;
leveloftrust: string;
lastsignedin: string;
};
export const PatientInfoFragment = graphql(/* GraphQL */ `
fragment PatientInfo on Patient {
addresses {
city
lines
postalCode
}
birthDate
email
gender
id
name {
firstName
lastName
}
status {
lastSignInAt
levelOfTrust
}
}
`);
interface PatientInfoProps {
patient: FragmentType&lt;typeof PatientInfoFragment&gt;;
}
export function PatientInfo(props: PatientInfoProps) {
const patient = useFragment(PatientInfoFragment, props.patient);
const [value, setValue] = React.useState&lt;Dayjs | null&gt;(
dayjs(patient.birthDate)
);
const genderValueArray = Object.values(Gender);
const [disabled, setDisabled] = useState(true);
const { register, handleSubmit } = useForm&lt;Inputs&gt;({
defaultValues: {
firstName: patient.name?.firstName ?? &#39;&#39;,
lastName: patient.name?.lastName ?? &#39;&#39;,
birthdate: patient.birthDate ?? &#39;&#39;,
country: &#39;&#39;,
gender: patient.gender,
email: patient.email ?? &#39;&#39;,
leveloftrust: patient.status?.levelOfTrust,
lastsignedin: patient.status?.lastSignInAt,
postalcode: patient.addresses[0]?.postalCode ?? &#39;&#39;,
city: patient.addresses[0]?.city ?? &#39;&#39;,
street: patient.addresses[0]?.lines[0] ?? &#39;&#39;,
},
shouldUseNativeValidation: true,
});
const handleChange = React.useCallback(
(newValue: Dayjs | null) =&gt; setValue(newValue),
[]
);
const { t } = useTranslation();
const handleEditClick = useCallback(() =&gt; setDisabled(!disabled), [disabled]);
const renderInputField = React.useCallback(
(params: JSX.IntrinsicAttributes &amp; TextFieldProps) =&gt; {
return &lt;TextField {...params} /&gt;;
},
[]
);
const onSubmit = (data: any) =&gt; console.log(data);
return (
&lt;Card&gt;
&lt;CardContent&gt;
&lt;form onSubmit={handleSubmit(onSubmit)}&gt;
&lt;Grid container direction=&quot;row&quot; justifyContent=&quot;space-between&quot;&gt;
&lt;Grid item&gt;
&lt;Typography gutterBottom variant=&quot;h5&quot; component=&quot;div&quot;&gt;
{t(&#39;patient.info.title&#39;, &#39;Personal Information&#39;)}
&lt;/Typography&gt;
&lt;/Grid&gt;
&lt;Grid item&gt;
&lt;Grid container justifyContent=&quot;space-between&quot; sx={{ m: 1 }}&gt;
{!disabled &amp;&amp; (
&lt;Button
onClick={handleEditClick}
size=&quot;large&quot;
variant=&quot;outlined&quot;&gt;
Cancel
&lt;/Button&gt;
)}
&lt;Button
onClick={handleEditClick}
size=&quot;large&quot;
type=&quot;submit&quot;
variant=&quot;contained&quot;&gt;
{!disabled
? t(&#39;patient.setToComplete&#39;, &#39;Set to complete&#39;)
: t(&#39;patient.edit&#39;, &#39;Edit&#39;)}
&lt;/Button&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;Grid container direction=&quot;row&quot;&gt;
&lt;Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;firstName&#39;, { required: &#39;Field needs to be filled out&#39; })}
label=&quot;Name&quot;
name=&quot;firstName&quot;
id=&quot;component-outlined&quot;
disabled={disabled}
/&gt;
&lt;/Grid&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;lastName&#39;, {
required: &#39;Field needs to be filled out&#39;,
})}
label=&quot;lastname&quot;
name=&quot;lastName&quot;
id=&quot;component-outlined&quot;
disabled={disabled}
/&gt;
&lt;/Grid&gt;
&lt;Grid item sx={{ width: &#39;274.67px&#39; }}&gt;
&lt;LocalizationProvider dateAdapter={AdapterDayjs}&gt;
&lt;DesktopDatePicker
{...register(&#39;birthdate&#39;, {
required: &#39;Field needs to be filled out&#39;,
})}
label=&quot;Birthdate&quot;
inputFormat=&quot;MM/DD/YYYY&quot;
value={value}
onChange={handleChange}
renderInput={renderInputField}
disabled={disabled}
/&gt;
&lt;/LocalizationProvider&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;street&#39;)}
id=&quot;component-outlined&quot;
label=&quot;Street&quot;
name=&quot;street&quot;
disabled={disabled}
/&gt;
&lt;/Grid&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;postalcode&#39;)}
id=&quot;component-outlined&quot;
label=&quot;Postal code&quot;
name=&quot;postalCode&quot;
disabled={disabled}
/&gt;
&lt;/Grid&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;city&#39;)}
id=&quot;component-outlined&quot;
label=&quot;City&quot;
name=&quot;city&quot;
disabled={disabled}
/&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;country&#39;)}
id=&quot;component-outlined&quot;
label=&quot;Country&quot;
name=&quot;country&quot;
disabled={disabled}
/&gt;
&lt;/Grid&gt;
&lt;Grid item&gt;
&lt;TextField
sx={{ width: &#39;242.67px&#39; }}
id=&quot;outlined-select-gender&quot;
select
{...register(&#39;gender&#39;)}
label=&quot;Gender&quot;
disabled={disabled}
value={patient.gender}&gt;
{genderValueArray.map(option =&gt; (
&lt;MenuItem key={option} value={option}&gt;
{option}
&lt;/MenuItem&gt;
))}
&lt;/TextField&gt;
&lt;/Grid&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;email&#39;)}
id=&quot;component-outlined&quot;
label=&quot;Email&quot;
name=&quot;email&quot;
disabled
/&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;leveloftrust&#39;)}
id=&quot;component-outlined&quot;
label=&quot;Level of trust&quot;
name=&quot;leveloftrust&quot;
disabled
/&gt;
&lt;/Grid&gt;
&lt;Grid item&gt;
&lt;TextField
{...register(&#39;lastsignedin&#39;)}
id=&quot;component-outlined&quot;
label=&quot;Last signed in&quot;
name=&quot;lastsignedin&quot;
disabled
/&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;/form&gt;
&lt;/CardContent&gt;
&lt;/Card&gt;
);
}

答案1

得分: 0

If you're using React Hook Form with MUI Textfield, you'll need to use the Controller component wrapper from react-hook-form for your MUI Textfield components.

View Integrating with UI Libraries

For example, you would grab the Input component from MUI's Core library instead:

import Input from "@material-ui/core/Input";

Then in your form, you'd wrap it using Controller like:

<Controller
  name="firstName"
  control={control}
  render={({ field }) => <Input {...field} />}
/>

Then MUI Input has error (boolean) and helperText (string) as available properties on the Input component. For example using Formik (but any form library would work with MUI):

<TextField
  id="password"
  name="password"
  label="Password"
  type="password"
  value={formik.values.password}
  onChange={formik.handleChange}
  error={!!formik.errors.password && formik.touched.password}
  helperText={formik.touched.password && formik.errors.password}
  required
/>

Otherwise, reviewing their documentation on how to Handle Errors, it appears with no library they have you handle error output manually using the errors object from formState. You'd destructure that data like:

const { register, formState: { errors }, handleSubmit } = useForm();

Finally, they link a very handy CodeSandbox which uses a @hookform/error-message library that can wrap regular HTML inputs. If you want to stick with MUI, I'd go with the helperText and error properties.

英文:

If you're using React Hook Form with MUI Textfield, you'll need to use the Controller component wrapper from react-hook-form for your MUI Textfield components.

View Integrating with UI Libraries

For example, you would grab the Input component from MUI's Core library instead:

import Input from &quot;@material-ui/core/Input&quot;;

Then in your form you'd wrap it using Controller like:

&lt;Controller
name=&quot;firstName&quot;
control={control}
render={({ field }) =&gt; &lt;Input {...field} /&gt;}
/&gt;

Then MUI Input has has error boolean and helperText string as available properties on the Input component. For example using Formik (but any form library would work with MUI):

&lt;TextField
id=&quot;password&quot;
name=&quot;password&quot;
label=&quot;Password&quot;
type=&quot;password&quot;
value={formik.values.password}
onChange={formik.handleChange}
error={!!formik.errors.password &amp;&amp; formik.touched.password}
helperText={formik.touched.password &amp;&amp; formik.errors.password}
required
/&gt;

Otherwise, reviewing their documentation on how to Handle Errors, it appears with no library they have you handle error output manually using the errors object from formState. You'd destructure that data like:

const { register, formState: { errors }, handleSubmit } = useForm();

Finally, they link a very handy CodeSandbox which uses a @hookform/error-message library that can wrap regular HTML inputs. If you want to stick with MUI, I'd go with the helperText and error properties.

huangapple
  • 本文由 发表于 2023年2月10日 04:14:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75403965.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定