【React全家桶入门之五】组件化表单/表单控件

问题

上一篇我们实现一个最基本的表单验证。

如果我们想要再写一个添加图书的功能,以同样的方式去写就会发现会出现很多重复的代码。因为所有的验证代码都是耦合在组件中的,没有办法实现复用。

重复代码是混乱的根源!

既然我们用了React,那我们是不是可以用组件化的方式去给表单验证这些逻辑解耦呢?

高阶组件:formProvider

什么是高阶组件?

高阶组件就是返回组件的组件(函数)

为什么要通过一个组件去返回另一个组件?

使用高阶组件可以在不修改原组件代码的情况下,修改原组件的行为或增强功能。

我们现在已经有了带有表单校验功能的添加用户的表单,这里的表单有3个字段:name、age、gender,并且每个字段都有它自己的校验规则和对应的错误信息。

要做一个添加图书的功能,图书的表单有name、price、owner_id三个字段,一样地,每个字段有它自己的校验规则和错误信息。

仔细想想,每当我们需要写一个表单的时候,都需要有一个地方来保存表单字段的值(state),有一个函数来处理表单值的更新和校验(handleValueChange),这些东西我们可以用高阶组件来封装。

而添加用户的表单和添加图书的表单之间的不同之处仅仅是表单字段以及字段的默认值、校验规则和错误信息

那么我们的高阶组件模型就出来了:

function formProvider (fields) {
   
  return function (Comp) {
   
    constructor (props) {
      super(props);
      this.state = {
        form: {...},
        formValid: false // 加了一个formValid用来保存整个表单的校验状态
      };
    }
    handleValueChange (field, value) {...}
    class FormComponent extends React.Component {
      render () {
        const {form, formValid} = this.state;
        return (
          <Comp {
    ...this.props} form={form} formValid={formValid} onFormChange={this.handleValueChange}/>
        );
      }
    }

    return FormComponent;
  }
}

formProvider接收一个fields参数,并返回一个函数,这个函数接收一个组件作为参数并返回一个组件,所以它的用法是这样的:

UserAdd = formProvider(fields)(UserAdd);

经过formProvider处理后的UserAdd组件会得到额外的props:

  • form
  • formValid
  • onFormChange

/src下新建一个目录utils,新建formProvider.js文件,写入具体的代码实现:

import React from 'react';

function formProvider (fields) {
   
  return function (Comp) {
   

    const initialFormState = {};
    for (const key in fields) {
      initialFormState[key] = {
        value: fields[key].defaultValue,
        error: ''
      };
    }

    class FormComponent extends React.Component {
      constructor (props) {
        super(props);
        this.state = {
          form: initialFormState,
          formValid: false
        };

        this.handleValueChange = this.handleValueChange.bind(this);
      }
      handleValueChange (fieldName, value) {
        const { form } = this.state;

        const newFieldState = {value, valid: true, error: ''};

        const fieldRules = fields[fieldName].rules;

        for (let i = 0; i < fieldRules.length; i++) {
          const {pattern, error} = fieldRules[i];
          let valid = false;
          if (typeof pattern === 'function') {
            valid &
  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 40
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值