React Hook Forms 如何使用 Typescript 将错误作为道具传递

React Hook Forms How to pass the errors as a props using Typescript

我正在定义一个 useForm。

const { handleSubmit, control, errors } = useForm<{email: string}>();

现在我正在创建一个单独的组件来输入,我将传递我在上面创建的 useForm 道具。

这就是组件的样子。

type Props<T> = {
  name: FieldName<T>;
  control: Control<T>;
  errors: FieldErrors<T>;
};

const ControlTextInput = <T extends {}>({
  name,
  control,
  errors,
}: Props<T>) => {
  return (
   
    <Controller
    name={name}
    control={control}
    rules={{
      required:'this is required',
    }}
    render={({ onChange }) => (
        <>
            <TextInput
                onChangeText={(text) => {
                onChange(text);
                }}
            />
            {/* Show my error here */}
            {errors.email && (
                <Text style={{ color: "red" }}>
                    {errors.email?.message}
                </Text>
            )}
      </>
    )}
  />
  );
};

我想这样使用组件。

   <ControlTextInput<AnyObject>
                    name="email"
                    errors={errors}
                    control={control}
                  />

当我将鼠标悬停在 errors.email 上时出现此错误

我找到解决方案的方法是使用错误类型 any errors?: any;

使用lodash get函数 const errName = get(errors, name);

然后我可以得到错误如下。

{errName && <Text style={{ color: "red" }}>{errName.message}</Text>}

React Hook Form 公开类型 UseControllerProps,它接受通用类型 T,它推断您的输入值类型或换句话说 FieldValues 类型。最初,您通过将有关字段的类型传递给 useForm 挂钩来定义 FieldValues 类型(请参阅下面的 MyInputTypes)。

interface MyInputTypes {
  email: string;
  password: string;
}

const { register, handleSubmit, watch, formState: { errors } } = useForm<MyInputTypes>();

这意味着您可以创建扩展 UseControllerProps 并具有通用 T interface Props<T> extends UseControllerProps<T> {} 的接口。类型 UseControllerProps 已经包含 namecontrol 的类型定义,因此您不需要在界面中单独定义它们(除非您想要或有特殊要求/原因)所以)。关于 errors 适当的解决方案 Imo(因为您只需要有关单个字段的错误)将直接传递类型为 FieldError | undefined 的特定错误。结果如下代码所示。

interface Props<T> extends UseControllerProps<T> {
  error: FieldError | undefined
}

然后您可以简单地使用您的 ControlTextInput,如下所示。

<ControlTextInput name="email" error={errors.email} />

在组件(使用 ControlTextInput)中,您的通用 T 必须扩展 FieldValues,因为最终,正是这种类型推断出有关字段的类型。

以ControlTextInput为例

import React from 'react';
import { Controller, FieldError, FieldValues, UseControllerProps } from 'react-hook-form';

interface Props<T> extends UseControllerProps<T> {
  error: FieldError | undefined;
}

const ControlTextInput = <T extends FieldValues>({ name, control, error }: Props<T>) => {
  return (
    <Controller
      name={name}
      control={control}
      rules={{
        required: 'This is required',
      }}
      render={({ field: { onChange } }) => (
        <>
          <input
            onChange={(text) => {
              onChange(text);
            }}
          />
          {error && <span style={{ color: 'red' }}>{error?.message}</span>}
        </>
      )}
    />
  );
};

export default ControlTextInput;

作为使用 ControlTextInput 的示例组件

import React, { FunctionComponent } from 'react';
import { useForm } from 'react-hook-form';
import ControlTextInput from './ControlTextInput';

interface InputTypes {
  email: string;
  password: string;
}

const Foo: FunctionComponent = () => {
  const {
    formState: { errors },
  } = useForm<InputTypes>();
  return <ControlTextInput name='email' error={errors.email} />;
};

export default Foo;

这里有现成代码的屏幕截图,它们或多或少地模仿了您的方法和解决方案(与上面的 Whosebug 新代码相同)。

ControlTextInput

Component which uses ControlTextInput