ext*_*eck 18 reactjs yup react-hook-form
我正在使用react-hook-form渲染自定义组件Controller
。
如果使用时出现错误register
,焦点正常,但Controller不正常。
当自定义组件仅处理单个输入时,我能够找到一种处理错误的方法,但当它有多个输入时,我找不到处理错误的方法。
\n表单.js
\nimport { Controller, useForm } from "react-hook-form";\nimport CustomInput from "./CustomInput";\nimport * as yup from "yup";\n\nconst schema = yup.object({\n name: yup.object().shape({\n first: yup.string().required(),\n last: yup.string().required(),\n }),\n});\nfunction Form() {\n const {\n handleSubmit,\n control,\n formState: { errors },\n } = useForm({\n defaultValues: { name: { first: "", last: "" } },\n resolver: yupResolver(schema),\n });\n\n const onSubmit = (data) => console.log(data);\n\n return (\n <form onSubmit={handleSubmit(onSubmit)}>\n <Controller\n name="name"\n control={control}\n rules={{ required: true }}\n render={({ field }) => (\n <CustomInput\n value={field.value}\n onChange={(value) => field.onChange(value)}\n errors={errors}\n />\n )}\n />\n <button type="submit">Send</button>\n </form>\n );\n}\n\nexport default Form;\n
Run Code Online (Sandbox Code Playgroud)\n自定义输入.js
\nfunction CustomInput({ value, onChange, errors }) {\n const changeFirst = (e) => {\n onChange({ first: e.target.value, last: value?.last });\n };\n\n const changeLast = (e) => {\n onChange({ first: value?.first, last: e.target.value });\n };\n\n return (\n <div>\n <input type="text" value={value.first} onChange={changeFirst} />\n <input type="text" value={value.last} onChange={changeLast} />\n {errors?.name && (\n <p className="errmsg">\n {errors?.name?.first?.message || errors?.name?.last?.message}\n </p>\n )}\n </div>\n );\n}\n\nexport default CustomInput;\n
Run Code Online (Sandbox Code Playgroud)\n\xe2\x80\x8b当自定义组件中有多个输入时,如何获得错误焦点?
\nNea*_*arl 16
您可以setFocus
从 RHF 使用。首先,检测errors
对象何时发生变化,然后找到第一个包含该对象的字段并调用setFocus(field)
:
const {
setFocus,
formState: { errors },
...
} = useForm<FormValues>();
React.useEffect(() => {
const firstError = Object.keys(errors).reduce((field, a) => {
return !!errors[field] ? field : a;
}, null);
if (firstError) {
setFocus(firstError);
}
}, [errors, setFocus]);
Run Code Online (Sandbox Code Playgroud)
控制焦点的是“ref”,由于某种原因,当您使用控制器时,“ref”无法正确关联到底层元素,因此您必须使用“register”中的 ref 而不是“field”中的 ref。
import { FC } from 'react'
import { Controller, useFormContext } from 'react-hook-form'
import { TextField, TextFieldProps } from '@mui/material'
export const RhfTextField: FC<{ name: string } & TextFieldProps> = ({
name,
...rest
}) => {
const { control, register } = useFormContext()
return (
<Controller
control={control}
name={name}
defaultValue=""
render={({ field, fieldState: { error } }) => (
<TextField
{...rest}
{...field}
ref={register(name).ref} // overriding field.ref
// you can do {...register(name)} and omit {...field}
// but showing this explicitly for demonstration purposes
error={!!error}
helperText={error?.message ?? ''}
/>
)}
/>
)
}
Run Code Online (Sandbox Code Playgroud)
根据@NearHuscarl 的回答,我创建了打字稿版本:
React.useEffect(() => {
const firstError = (
Object.keys(errors) as Array<keyof typeof errors>
).reduce<keyof typeof errors | null>((field, a) => {
const fieldKey = field as keyof typeof errors;
return !!errors[fieldKey] ? fieldKey : a;
}, null);
if (firstError) {
setFocus(firstError);
}
}, [errors, setFocus]);
Run Code Online (Sandbox Code Playgroud)
受arcanereinz 解决方案的启发,您可以使用inputRef
而不需要定义ref
。
我认为 MUI 中有一个错误,这种行为真的很奇怪
工作codesandbox在这里https://codesandbox.io/s/sweet-panna-ttste0?file=/src/App.tsx
import { Controller, useForm } from "react-hook-form";
import TextField from "@mui/material/TextField";
export default function App() {
const { handleSubmit, control } = useForm();
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Controller
name="foo"
control={control}
rules={{ required: true }}
render={({ field: { ref, ...field }, fieldState }) => (
<TextField
fullWidth
variant="outlined"
error={Boolean(fieldState.error)}
inputRef={ref}
{...field}
/>
)}
/>
<button type="submit">submit</button>
</form>
);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
32577 次 |
最近记录: |