英文:
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
This is how i have done it:
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) {
const patient = useFragment(PatientInfoFragment, props.patient);
const [value, setValue] = React.useState<Dayjs | null>(
dayjs(patient.birthDate)
);
const genderValueArray = Object.values(Gender);
const [disabled, setDisabled] = useState(true);
const { register, handleSubmit } = useForm<Inputs>({
defaultValues: {
firstName: patient.name?.firstName ?? '',
lastName: patient.name?.lastName ?? '',
birthdate: patient.birthDate ?? '',
country: '',
gender: patient.gender,
email: patient.email ?? '',
leveloftrust: patient.status?.levelOfTrust,
lastsignedin: patient.status?.lastSignInAt,
postalcode: patient.addresses[0]?.postalCode ?? '',
city: patient.addresses[0]?.city ?? '',
street: patient.addresses[0]?.lines[0] ?? '',
},
shouldUseNativeValidation: true,
});
const handleChange = React.useCallback(
(newValue: Dayjs | null) => setValue(newValue),
[]
);
const { t } = useTranslation();
const handleEditClick = useCallback(() => setDisabled(!disabled), [disabled]);
const renderInputField = React.useCallback(
(params: JSX.IntrinsicAttributes & TextFieldProps) => {
return <TextField {...params} />;
},
[]
);
const onSubmit = (data: any) => console.log(data);
return (
<Card>
<CardContent>
<form onSubmit={handleSubmit(onSubmit)}>
<Grid container direction="row" justifyContent="space-between">
<Grid item>
<Typography gutterBottom variant="h5" component="div">
{t('patient.info.title', 'Personal Information')}
</Typography>
</Grid>
<Grid item>
<Grid container justifyContent="space-between" sx={{ m: 1 }}>
{!disabled && (
<Button
onClick={handleEditClick}
size="large"
variant="outlined">
Cancel
</Button>
)}
<Button
onClick={handleEditClick}
size="large"
type="submit"
variant="contained">
{!disabled
? t('patient.setToComplete', 'Set to complete')
: t('patient.edit', 'Edit')}
</Button>
</Grid>
</Grid>
</Grid>
<Grid container direction="row">
<Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}>
<Grid item>
<TextField
{...register('firstName', { required: 'Field needs to be filled out' })}
label="Name"
name="firstName"
id="component-outlined"
disabled={disabled}
/>
</Grid>
<Grid item>
<TextField
{...register('lastName', {
required: 'Field needs to be filled out',
})}
label="lastname"
name="lastName"
id="component-outlined"
disabled={disabled}
/>
</Grid>
<Grid item sx={{ width: '274.67px' }}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DesktopDatePicker
{...register('birthdate', {
required: 'Field needs to be filled out',
})}
label="Birthdate"
inputFormat="MM/DD/YYYY"
value={value}
onChange={handleChange}
renderInput={renderInputField}
disabled={disabled}
/>
</LocalizationProvider>
</Grid>
</Grid>
<Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}>
<Grid item>
<TextField
{...register('street')}
id="component-outlined"
label="Street"
name="street"
disabled={disabled}
/>
</Grid>
<Grid item>
<TextField
{...register('postalcode')}
id="component-outlined"
label="Postal code"
name="postalCode"
disabled={disabled}
/>
</Grid>
<Grid item>
<TextField
{...register('city')}
id="component-outlined"
label="City"
name="city"
disabled={disabled}
/>
</Grid>
</Grid>
<Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}>
<Grid item>
<TextField
{...register('country')}
id="component-outlined"
label="Country"
name="country"
disabled={disabled}
/>
</Grid>
<Grid item>
<TextField
sx={{ width: '242.67px' }}
id="outlined-select-gender"
select
{...register('gender')}
label="Gender"
disabled={disabled}
value={patient.gender}>
{genderValueArray.map(option => (
<MenuItem key={option} value={option}>
{option}
</MenuItem>
))}
</TextField>
</Grid>
<Grid item>
<TextField
{...register('email')}
id="component-outlined"
label="Email"
name="email"
disabled
/>
</Grid>
</Grid>
<Grid
container
sx={{ margin: 1 }}
rowSpacing={3}
spacing={{ md: 4 }}>
<Grid item>
<TextField
{...register('leveloftrust')}
id="component-outlined"
label="Level of trust"
name="leveloftrust"
disabled
/>
</Grid>
<Grid item>
<TextField
{...register('lastsignedin')}
id="component-outlined"
label="Last signed in"
name="lastsignedin"
disabled
/>
</Grid>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
);
}
答案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 "@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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论