如何用React实现一个antd表单组件

380 阅读2分钟

前言

在平日业务开发中,为了节省时间,可能大部分程序员都是习惯性的打开antd官网,选择组件,展开copy就完事,过后可能很少去理解怎么实现的,比如我们常用的Form表单,怎么用input标签实现数据的数据的搜集,报错的显示,以及实现的设计模式等。

小知识

什么是高阶组件-HOC? 为了提高组件复用率,可测试性,就要保证组件功能单一性;但是诺要满足复杂需求就要扩展功能单一的组件,所以在React⾥就有了 HOC(Higher-Order Components)的概念。简单的说就是参数为组件,返回值为新组件的函数

简单例子

// HocPage.js
import React, {Component} from "react";
// hoc: 是⼀个函数,接收⼀个组件,返回另外⼀个组件
//这⾥⼤写开头的Cmp是指function或者class组件
const foo = Cmp => props => {
    return (
        <div className="border">
        <Cmp {...props} />
        </div>
    );
};
function Child(props) {
    return <div> Child {props.name}</div>; 
}
const Foo = foo(Child);
export default class HocPage extends Component {
   render() {
       return (
           <div>
               <h3>HocPage</h3>
               <Foo name="msg" />
           </div>
       );
   }
}

表单组件设计思路

  • 表单组件要求实数据收集校验提交等特性,可通过高级组件扩展
  • 高阶组件给表单组件传递一个input组件包装函数接管其输入事件并统一管理表单数据
  • 高阶组件给表单组件传递一个校验函数使其具备数据校验功能

组件实现

  • 表单基本结构,创建MyFormPage.js
  import React, { Component } from "react";
  import MyFormCreate from "../conponents/MyFormCreate";
  //校验规则
  const nameRules = { required: true, message: "please input ur name"};
  const passwordRules = { required: true, message: "please input ur password"};
  export default MyFormCreate(
    class MyFormPage extends Component {
      submit = () => {
        const { getFieldsValue, getFieldValue, validateFields } = this.props;
        validateFields((err, values) => {
          if (err) {
            console.log("err", err);
          } else {
            console.log("success", values);
          }
        });
        getFieldValue("name");
      };
      render() {
        const { getFieldDecorator } = this.props;
        return (
          <div>
            <h3>MyFormPage</h3>
            {getFieldDecorator("name", { rules: [nameRules] })(
              <input type="text" placeholder="please input ur name" />
            )}
            {getFieldDecorator("password", { rules: [passwordRules] })(
              <input type="password" placeholder="please input ur password" />
            )}
            <button onClick={this.submit}>提交</button>
          </div>
        );
      }
    }
  );
  ​
  • 高阶组件MyFormCreate扩展现有表单,./components/MyFormCreate.js
  import React, { Component } from "react";
  export default function MyFormCreate(Cmp) {
    return class extends Component {
      constructor(props) {
        super(props);
        this.state = {};
        this.options = {};
      }
      handleChange = (e) => {
        let { name, value } = e.target;
        this.setState({ [name]: value });
      };
      getFieldDecorator = (field, option) => {
        this.options[field] = option;
        return (InputCmp) =>
          React.cloneElement(InputCmp, {
            name: field,
            value: this.state[field] || "",
            onChange: this.handleChange, //控件change
          });
      };
      getFieldsValue = () => {
        return { ...this.state };
      };
      getFieldValue = (field) => {
        return this.state[field];
      };
      validateFields = (callback) => {
        let errors = {};
        const state = { ...this.state };
        for (let field in this.options) {
          if (state[field] === undefined) {
            errors[field] = "error";
          }
          console.log("item", field); //sy-log
        }
        if (JSON.stringify(errors) === "{}") {
          // 没有错误信息
          callback(undefined, state);
        } else {
          // 有错误信息,返回
          callback(errors, state);
        }
      };
      render() {
        return (
          <div className="border">
            <Cmp
              {...this.props}
              getFieldDecorator={this.getFieldDecorator}
              getFieldsValue={this.getFieldsValue}
              getFieldValue={this.getFieldValue}
              validateFields={this.validateFields}
            />
          </div>
        );
      }
    };
  }
  

总结

⾼阶组件(HOC)是 React 中⽤于复⽤组件逻辑的⼀种⾼级技巧。 HOC ⾃身不是 React API 的⼀部分,它是⼀种基于 React 的组合特性⽽形成的设计模式。注意 不要再render方法中使用HOC,因为每次在render中调用HOC那么每次得到组件都是新组件,这样就会触发React的Diff算法,执行挂载与卸载的操作,影响不必要的性能问题。