使用 AntD 样式的 React Hook 表单

Posted

技术标签:

【中文标题】使用 AntD 样式的 React Hook 表单【英文标题】:React Hook Form with AntD Styling 【发布时间】:2020-03-01 08:54:04 【问题描述】:

我正在尝试弄清楚如何将 react-hook-form 与 antd 前端一起使用。

我已经制作了这个表单,它似乎可以正常工作(它是多部分表单向导的第 1 部分),只是没有显示错误消息。

谁能看到我在合并这两个表单系统时做错了什么?

我没有收到任何错误,但我认为我已要求两个表单字段都必须填写,但如果我在未完成的情况下按提交,则不会显示错误消息。

import React from "react";
import useForm from "react-hook-form";
import  BrowserRouter as Router, Route  from "react-router-dom";
import  StateMachineProvider, createStore  from "little-state-machine";
import  withRouter  from "react-router-dom";
import  useStateMachine  from "little-state-machine";

import updateAction from "./updateAction";
import  Button, Form, Input,  Divider, Layout, Typography, Skeleton, Switch, Card, Icon, Avatar  from 'antd';


const  Content  = Layout 
const  Text, Paragraph  = Typography;
const  Meta  = Card;

createStore(
  data: 
);

const General = props => 
  const  register, handleSubmit, errors  = useForm();
  const  action  = useStateMachine(updateAction);
  const onSubit = data => 
    action(data);
    props.history.push("./ProposalMethod");
  ;


  return (

      <div>

        <Content
          style=
            background: '#fff',
            padding: 24,
            margin: "auto",
            minHeight: 280,
            width: '70%'
          
        >
        <Form onSubmit=handleSubmit(onSubit)>

          <h2>Part 1: General</h2>
            <Form.Item label="Title" >
              <Input 
                name="title" 
                placeholder="Add a title" 
                ref=register( required: true ) 
              />
              errors.title && 'A title is required.'
            </Form.Item>
            <Form.Item label="Subtitle" >
              <Input 
                name="subtitle" 
                placeholder="Add a subtitle" 
                ref=register( required: true ) 
              />
              errors.subtitle && 'A subtitle is required.'
            </Form.Item>
            <Form.Item>
              <Button type="secondary" htmlType="submit">
                Next
              </Button>
            </Form.Item>

        </Form>

        </Content>
      </div>  
  );
;

export default withRouter(General);

【问题讨论】:

当你有内置的getFieldDecorator 时为什么要使用第三方验证器,另外,你假设这种适用于html 组件的钩子将适用于自定义组件,如Form,@ 987654325@等等。 什么意思?我试图使用带有钩子的 antd 样式。我想不通,所以我放弃了,现在使用带有钩子形式的常规 css。 我不明白带钩子的样式与您的要求有何关系 我想你是在问我为什么要尝试使用 antd。这就是为什么 - 样式与应用程序的其余部分一致。仅供参考:它不起作用,因为 antd 不支持不受控制的组件 我没问你为什么用antd,我问你为什么用react-hook-formantd支持不受控制的组件,就像我在第一条评论中提到的那样。 【参考方案1】:

关于编写这样的代码:

<Input
  name="subtitle"
  placeholder="Add a subtitle"
  ref=register( required: true )
/>

您假设 Input 引用绑定到 input,但事实并非如此。

其实你需要绑定到inputRef.input

你可以用下面的代码检查一下:

const App = () => 
  const inputRef = useRef();
  const inputRefHtml = useRef();

  useEffect(() => 
    console.log(inputRef.current);
    console.log(inputRefHtml.current);
  );

  return (
    <FlexBox>
      <Input ref=inputRef />
      <input ref=inputRefHtml />
    </FlexBox>
  );
;
# Logs
Input props: Object, context: Object, refs: Object, updater: Object, saveClearableInput: function ()…

<input></input>

注意antd是一个完整的UI库(使用第3方“助手”应该“闯红灯”),特别是Form实现了一个验证器,你可以看到a variety of examples in docs。

【讨论】:

【参考方案2】:

react-hook-form 作者在这里。 Antd Input 组件并没有真正暴露内部ref,所以你必须在useEffect 期间register,并在onChange 期间更新值,例如:

const  register, setValue  = useForm();

useEffect(() => 
  register( name: 'yourField' ,  required: true );
, [])

<Input name="yourField" onChange=(e) => setValue('yourField', e.target.value)

我已经构建了一个包装器组件,使 antd 组件集成更容易:https://github.com/react-hook-form/react-hook-form-input

import React from 'react';
import useForm from 'react-hook-form';
import  RHFInput  from 'react-hook-form-input';
import Select from 'react-select';

const options = [
   value: 'chocolate', label: 'Chocolate' ,
   value: 'strawberry', label: 'Strawberry' ,
   value: 'vanilla', label: 'Vanilla' ,
];

function App() 
  const  handleSubmit, register, setValue, reset  = useForm();

  return (
    <form onSubmit=handleSubmit(data => console.log(data))>
      <RHFInput
        as=<Select options=options />
        rules= required: true 
        name="reactSelect"
        register=register
        setValue=setValue
      />
      <button
        type="button"
        onClick=() => 
          reset(
            reactSelect: '',
          );
        
      >
        Reset Form
      </button>
      <button>submit</button>
    </form>
  );

【讨论】:

谢谢布鲁斯。不确定我是否遵循这个。来自 antd 的错误消息适用于多步骤表单的第一步,但不适用于后续步骤。如果我发现了什么,我会继续尝试并更新此页面。 你想在我们的频谱频道发布这个问题吗?我很乐意在那里提供帮助。 如果要触发验证,setValue('xxx', value, true) 网站上都有记录 谢谢@Bruce - 我会再试一次。 这现在是 RHF 内置的,所以你应该使用 Controller 组件来包装它。【参考方案3】:

如果有人仍然对接近 Ant 提供的表单输入的默认样式感兴趣,下面是我如何让它工作的:

import  Form, Button, Input  from 'antd';
import  useForm, Controller  from 'react-hook-form';

function MyForm() 
    const  control, handleSubmit, errors, setValue  = useForm();
    const emailError = errors.email && 'Enter your email address';

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

    const EmailInput = (
        <Form.Item>
            <Input
                type="email"
                placeholder="Email"
                onChange=e => setValue('email', e.target.value, true)
                onBlur=e => setValue('email', e.target.value, true)
            />
        </Form.Item>
    );


    return (
        <form onSubmit=handleSubmit(onSubmit)>
            <Controller 
                as=EmailInput 
                name="email" 
                control=control 
                defaultValue=""
                rules=
                    required: true
                
                validateStatus=emailError ? 'error' : ''
                help=emailError
            />

            <Button block type="primary" htmlType="submit">
                Submit
            </Button>
        </form>
    );

Codesandbox sample

【讨论】:

感谢分享-今晚我会看看这个。我仍在努力解决这个问题。【参考方案4】:

这是我的工作方法:

const Example = () => 

 const  control, handleSubmit, errors  = useForm()

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

  return (
    <Form onSubmit=handleSubmit(onSubmit)>
      <Controller
        name="email"
        control=control
        rules= required: "Please enter your email address" 
        as=
          <Form.Item
            label="name"
            validateStatus=errors.email && "error"
            help=errors.email && errors.email.message
          >
            <Input />
          </Form.Item>
        
      />
      <Button htmlType="submit">Submit</Button>
    </Form>
  )

【讨论】:

【参考方案5】:

在 Ant Design v4.x + react-hook-form v6.x 中。我们可以正常实现

import  useForm, Controller, SubmitHandler  from 'react-hook-form';
import * as yup from 'yup';
import  yupResolver  from '@hookform/resolvers/yup';

import  useIntl  from 'react-intl';
import  Input, Button, Form  from 'antd';

const SignInSchema = yup.object().shape(
  email: yup.string().email().required(),
  password: yup.string().required('required').min(6, 'passwordMin'),
);

interface PropTypes 
  defaultValues?: 
    email: string;
    password: string;
  ;
  handleFormSubmit: SubmitHandler< email: string; password: string >;


function SignInForm( defaultValues, handleFormSubmit : PropTypes) 
  const intl = useIntl();
  const  handleSubmit, control, errors  = useForm(
    defaultValues,
    resolver: yupResolver(SignInSchema),
  );

  return (
    <Form onFinish=handleSubmit(handleFormSubmit)>
      <Form.Item
        validateStatus=errors && errors['email'] ? 'error' : ''
        help=errors.email?.message
      >
        <Controller
          as=Input
          name="email"
          autoComplete="email"
          control=control
          placeholder=intl.formatMessage( id: 'AUTH_INPUT_EMAIL' )
        />
      </Form.Item>
      <Form.Item
        validateStatus=errors && errors['password'] ? 'error' : ''
        help=errors.password?.message
      >
        <Controller
          as=Input
          name="password"
          type="password"
          control=control
          autoComplete="new-password"
          defaultValue=""
          placeholder=intl.formatMessage( id: 'AUTH_INPUT_PASSWORD' )
        />
      </Form.Item>

      <Button type="primary" htmlType="submit">
        intl.formatMessage( id: 'SIGN_IN_SUBMIT_BUTTON' )
      </Button>
    </Form>
  );


export default SignInForm;

【讨论】:

嗨,在 Form.Item 中添加 validateStatus 和帮助道具时,我收到错误 index.js:1 警告:在 StrictMode 中不推荐使用 findDOMNode。 findDOMNode 被传递了一个 DomWrapper 的实例,它位于 StrictMode 中。相反,直接将 ref 添加到要引用的元素。在此处了解有关安全使用 refs 的更多信息:reactjs.org/link/strict-mode-find-node。请让我知道如何解决它。非常感谢! @ĐặngKiên 这是 Antd 设计的问题,他们可能需要在下一个版本中进行较大的更改以修复此问题github.com/ant-design/ant-design/issues/27921

以上是关于使用 AntD 样式的 React Hook 表单的主要内容,如果未能解决你的问题,请参考以下文章

在 react-hook-form 中设置 DatePicker 的值(来自 antd)

react form 赋值

react hook+antd实现点击发送验证码功能

react+antd:Form表单校验不提示错误信息

antd v3 升级 v4

react+antd修改antd默认样式