reactjs 当react-hook-form控制器发生错误时如何聚焦?

2o7dmzc5  于 2022-11-22  发布在  React
关注(0)|答案(3)|浏览(184)

我正在使用react-hook-form的Controller呈现一个定制组件。
如果在使用register时发生错误,则焦点正常,但控制器不正常。
当自定义组件只处理一个输入时,我能够找到处理错误的方法,但当它有多个输入时,我找不到处理错误的方法。
Form.js

import { Controller, useForm } from "react-hook-form";
import CustomInput from "./CustomInput";
import * as yup from "yup";

const schema = yup.object({
  name: yup.object().shape({
    first: yup.string().required(),
    last: yup.string().required(),
  }),
});
function Form() {
  const {
    handleSubmit,
    control,
    formState: { errors },
  } = useForm({
    defaultValues: { name: { first: "", last: "" } },
    resolver: yupResolver(schema),
  });

  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="name"
        control={control}
        rules={{ required: true }}
        render={({ field }) => (
          <CustomInput
            value={field.value}
            onChange={(value) => field.onChange(value)}
            errors={errors}
          />
        )}
      />
      <button type="submit">Send</button>
    </form>
  );
}

export default Form;

CustomInput.js

function CustomInput({ value, onChange, errors }) {
  const changeFirst = (e) => {
    onChange({ first: e.target.value, last: value?.last });
  };

  const changeLast = (e) => {
    onChange({ first: value?.first, last: e.target.value });
  };

  return (
    <div>
      <input type="text" value={value.first} onChange={changeFirst} />
      <input type="text" value={value.last} onChange={changeLast} />
      {errors?.name && (
        <p className="errmsg">
          {errors?.name?.first?.message || errors?.name?.last?.message}
        </p>
      )}
    </div>
  );
}

export default CustomInput;

当自定义组件中有多个输入时,如何获得错误焦点?

agxfikkp

agxfikkp1#

你可以从RHF中使用setFocus。首先,检测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]);

unftdfkk

unftdfkk2#

根据@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]);

中 的 每 一 个

mjqavswn

mjqavswn3#

控件的焦点是“ref”,由于某种原因,当您使用Controller时,“ref”没有与底层元素正确关联,因此您必须从“register”而不是从“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 ?? ''}
        />
      )}
    />
  )
}

相关问题