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

use*_*830 11 typescript reactjs react-native react-hook-form

我正在定义一个 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>
            )}
      </>
    )}
  />
  );
};
Run Code Online (Sandbox Code Playgroud)

我想使用这样的组件。

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

Run Code Online (Sandbox Code Playgroud)

当我将鼠标悬停在errors.email 在此输入图像描述

Mat*_*ner 18

React Hook Form 公开了UseControllerProps接受泛型类型 T 的类型,该泛型类型 T 推断您的输入值类型或换句话说类型FieldValues。最初,您FieldValues通过传递有关要挂钩的字段的类型来定义类型useForm(见MyInputTypes下文)。

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

const { register, handleSubmit, watch, formState: { errors } } = useForm<MyInputTypes>();
Run Code Online (Sandbox Code Playgroud)

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

interface Props<T> extends UseControllerProps<T> {
  error: FieldError | undefined
}
Run Code Online (Sandbox Code Playgroud)

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

<ControlTextInput name="email" error={errors.email} />
Run Code Online (Sandbox Code Playgroud)

在组件(使用 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;
Run Code Online (Sandbox Code Playgroud)

作为使用 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;
Run Code Online (Sandbox Code Playgroud)

以下是带有现成代码的屏幕截图,这些代码或多或少地模仿了您的方法和解决方案(与上面的 StackOverflow 的新代码相同)。

控制文本输入

使用 ControlTextInput 的组件

  • 很好的答案,谢谢!我能够用正确的类型修复我的子组件。我必须使用 `&lt;T extends FieldValues&gt;` 声明我的 props 接口才能使其正常工作,如下所示: `interface Props&lt;T extends FieldValues&gt; extends UseControllerProps&lt;T&gt; {`,但除此之外,您的答案很清晰-解释道。欣赏它! (2认同)