美文网首页react专题
对ant-design表单之再次认识

对ant-design表单之再次认识

作者: cs0710 | 来源:发表于2017-09-03 14:57 被阅读1689次
本次写的是自己使用react的form表单的一些认识和使用总结。
1.react表单的不外乎是输入框、单选框、复选框等。但是在和html表单的相对比,差异还是蛮大的。

html表单是非受控组件。其表单组件中使用的属性名是value,在输入框的值改变的时候,里面的内容也会跟着改变。

<input value="input test" />
<textarea>textarea input</textarea>
<input type="radio" checked/> male
<input type="radio"/> female
<input type="checkbox" checked/> checkbox1
<input type="checkbox"/> checkbox2

react毕竟是js,它里面的表单是受控组件,一旦设置了value,渲染出来的 HTML 元素始终保持value 属性的值。

render () {
  return (
    <form>
      <input value="react input test" />
      <textarea defaultValue="react textarea input" />
      <input type="radio" defaultChecked/> male
      <input type="radio"/> female
      <input type="checkbox" defaultChecked/> checkbox1
      <input type="checkbox"/> checkbox2
    </form>
  )
}

但是对于原生的组件,都会支持onChange事件,在react中还是通过setState改变状态的值,重新渲染进而改变输入框的值。如果在初始化的时候就想展现默认值上面两种场景下的输入框都支持defaultValue属性。同样在对textarea使用的时候,react不再向html中那样通过子节点或者文本去设置它的值,而是通defaultValu去设置。radio、checkbox这些在html中作为非受控组件都是通过checked去实现一些功能,在react则是使用defaultChecked搭配onChange事件实现选择的切换,建议使用onChange时间替代onInput事件。

2.上面都是使用的原生的html控件,而下面的例子在reactJs中使用react封装的组件,又会有一些差异。
// test.jsx文件

import React from "react";
import { Form, Input, Button } from "antd"
const FormItem = Form.Item;
class Component extends React.Component {
    testEvent(e) {
        e.preventDefault();
        this.props.form.validateFields((err, values) => {
            if (err) {
                return;
            }
          const inputValue = values.initialValue;  // 可以看到在Input组件中设置                                                         defaultValue的值并拿不到,拿到的是                                                     testInitialValue
        });
          this.props.form.setFieldsValue({name: "myName"});  // 动态设置值
    }
    render() {
        const { getFieldDecorator } = this.props.form;
        return (
            <Form onSubmit={this.testEvent.bind(this)} layout="horizontal">
                <FormItem
                    label="用户名"
                >
                    {
                        getFieldDecorator("name", {
                            initialValue: "testInitialValue"
                        })(
                            <Input defaultValue="ahs" />
                        )
                    }
                </FormItem>
                <FormItem>
                    <Button htmlType="submit">测试按钮</Button>
                </FormItem>
            </Form>
        );
    }
}
const WrappedHorizontalLoginForm = Form.create()(Component);
export default WrappedHorizontalLoginForm;

通过上面这一个简单的小例子,我们在使用的时候会发现,在设置输入框的值时, 我们使用defaultValue在提交时并获取不到值,在react的api文档中说了,设置表单值默认使用的是initialValue,并且可以通过this.props.form.setFieldsValue来动态设置输入框的值,这里有一句原话就是动态设置输入框的值你不应该使用setState,因为setFieldsValue方法本质上就是调用的wrapper的setState方法。而我们在业务使用中对输入框进行设置值得时候使用的都是更改状态(setState),却很少使用过这个方法(setFieldsValue)去设置值。

注意:使用setFieldsValue要注意使用的生命周期,不要在componentWillReceiveProps这个生命周期中使用,因为在为睡醒设置值的时候,会继续执行该生命周期的方法,然后就会造成死循环。

3.关于在我们业务中使用的react的form表单与我使用过后的的体验感受以及自己的小建议

我们在业务中使用的form表单的时候,大多都是以一个方式写的,这种方式在看过之后,发现我们在代码中绕了做了多余的东西,就是在中间定义组件属性的时候,在自定义组件中又重复的去读了一遍值。也就是说,使用一个属性或者方法我们重复的走了一步,需要两次操作才能使用,下面就是一个例子。

import React from "react";
import { Form, Input, Button } from "antd"
const FormItem = Form.Item;
class Component extends React.Component {
    testEvent(e) {
        e.preventDefault();
        const refs = this.refs;
        refs.formTest.validateFields((err, values) => {
            if (err) {
                return;
            }
            console.log(values.name);
        });
        refs.formTest.setFieldsValue({name: "myName"});
    }
    render() {
        return (
            <FormTest
                ref="formTest"
                testEvent={this.testEvent.bind(this)} // 将方法放作为自定义组件的属性,这里                                                            只是简单的举一下例子,如果在表单需                                                         要的属性很多的话,就要写好多
            />
        )
    }
}
const FormTest = Form.create()((props) => {
    const { form, testEvent } = props; // 再去获取组件的属性,我认为这就是多走的一步,尤其是在                                        属性多的时候,还要全部将自定义组件的属性取出来,感觉                                          有些重复性太大
    const { getFieldDecorator } = form;
    return (
        <Form onSubmit={testEvent} layout="horizontal">
            <FormItem
                label="用户名"
            >
                {
                    getFieldDecorator("name", {
                        initialValue: "initialValue"
                    })(
                        <Input defaultValue="ahs" />
                    )
                }
            </FormItem>
            <FormItem>
                <Button htmlType="submit">提交</Button>
            </FormItem>
        </Form>
    );
});
export default Component;

在业务中我们大多都是这样使用的,这样写多了,回头看一下,确实是去了两遍相同的方法和属性,在react的form表单的弹出的模态框的实例中,它也是这么写的,这样对初次读代码的人来说也是有一点意外的。而我认为应该把form表单提出去,直接作为一个自定义的组件使用,这样起码可以保证不再去两次取得属性和方法,一次就够,直接写在form表单中,因为放在这里面的都是操作form的数据。

下面就是将form表单提出去,作为一个自定义的组件,其实这样写还有个好处就是,归根结底也是不再去重读性引用方法,就是表单校验的方法,以前都是放在父级组件中去自定义这些方法,再去子组件中使用,中间跨度也不小,做一个校验在代码量大的时候要找一些空间的名字,也不容易。当然,这只是我自己的感受罢了。

import React from "react";
import { Form, Input, Button } from "antd"
const FormItem = Form.Item;
import FormTest from "./test.jsx";  // 引用的是上面的2中的test.jsx文件
class Component extends React.Component {
    render() {
        return (
            <FormTest />
        )
    }
}
export default Component;

这样使用之后,第一感觉就是代码的逻辑更清晰了,不像放在一个页面里那么冗杂、混乱。这样操作表单的时候就会更加有针对性,而且,把可以把和表单有关的属性和方法都去定义在自定义的表单组件中,这样就只需要引用一次,不用在中间将那些在表单中需要的东西做个过渡了。对于业务中使用的那种,是不是可以考虑一下优化一下。

以上就是我在对form表单的使用和了解中发现的问题,更多的还是一些自己在使用过后的一些感受和体验,以及有哪些地方是否应该去优化。自己对架构知识还尚浅,有不对的地方,多多提出,我也会继续学习及时改正。

相关文章

网友评论

    本文标题:对ant-design表单之再次认识

    本文链接:https://www.haomeiwen.com/subject/tpgdjxtx.html