antd rapid development (Form article)
Foreword
As has been doing business in Taiwan, particularly the project background, but the background characteristics of the project are: a large number of lists and a large number of forms, will reduce the duplication of development efficiency, so here I summed up what use antd
components to build form
quick method. I hope to be useful.
Traditional Form build
First, build a form of traditional form, the code might look like this child
import React from 'react';
import { Form, Input } from 'antd';
@Form.create()
class MyTestForm extends React.Component {
render() {
const { form: { getFieldDecorator } } = this.props;
return(
<Form>
<Form.Item label='姓名'>
{
getFieldDecorator('username', {
rules: [
{
required: true,
message: '这是必填项'
}
]
})(<Input placeholder="placeholder" />)
}
</Form.Item>
<Form.Item label='密码'>
{
getFieldDecorator('password', {
rules: [
{
required: true,
message: '这是必填项'
}
]
})(<Input placeholder="placeholder" />)
}
</Form.Item>
</Form>
)
}
}
export default MyTestForm;
At present, only two individual tables, the code looks pretty clear, if this form is very complex forms, there are more form item, this code will be very long, it is not convenient maintenance and development, the most important again a big form, you'll still need to write so much code. This will affect the open efficiency.
Form optimized
What we want is, try to write less (not write) repetitive code so that a higher reusability of code. I did some this optimization, the main flow is shown:
Several major points:
- The lowest level, the most important part pulled out, that is,
BaseItem
the components,BaseItem
the ability to have is the ability to form, the ability of the two-way binding, pure components, does not contain any UI aspects of things. - Something the UI layer also pulled out separately, in order to facilitate future expansion of UI level. (For example, wanted to design their own set of UI style, only used directly to develop a new UI aspects of things, but the code instead of atomic layer assembly of the heart).
- Each form of information pulled into the configuration file so that the page maintenance more convenient.
Possible code
//BaseItem.js(原子层)
const BaseItem = (props) => {
const { form: { getFieldDecorator }, config } = props;
const { name, children, ...argv } = config;
return name ? getFieldDecorator(name, { ...argv })(children) : (children);
}
export default BaseItem;
//ItemLayout.js(UI组件)
import React from 'react';
import { Form } from 'antd';
//Layout也可以用自己的UI组件
const Layout = ({ config: { itemOptions }, children }) =>
<Form.Item { ...itemOptions } >{ children }</Form.Item>
const hidden = (isHidden) => {
const type = typeof(isHidden);
return (type === 'function' && isHidden()) || type === undefined || isHidden;
//默认是显示
}
class ItemLayout extends React.Component {
render() {
const { children } = this.props;
return(
<>
{
React.Children.map(
children, (child, i) => {
const { config: { isHidden, ...argv}} = child.props;
return hidden(isHidden) ? null : //具有隐藏表单项能力
React.cloneElement(
<Layout { ...argv }>{ child }</Layout>,
{
...children.props
}
)
}
)
}
</>
)
}
}
export default ItemLayout;
//config.js(配置文件)
import React from 'react';
import { Input } from 'antd';
export const formConfig = () => {
return [
{
itemOptions : { //Form.Item的api配置
label: '姓名'
//...argv
},
name: 'username',
initialValue: '',
rules: [],
children: <Input />
//...argv
},
{
itemOptions : {
label: '密码'
},
name: 'password',
initialValue: '',
rules: [],
children: <Input />,
isHidden: true //隐藏此项 默认是显示
},
{
itemOptions : {
label: '密码'
},
name: 'password',
initialValue: '',
rules: [],
children: <Input />,
isHidden: () => false //通过方法来动态显示隐藏
},
]
}
Support
antd Form
allapi
.Why use the configuration file is a function of the form? Because the parameters of the function can be realized for transferring data between pages and profiles.
So use a page, the code is as follows
import React from 'react';
import { Form, Input } from 'antd';
import { formConfig } from './config.js';
import BaseItem from './BaseItem';
import ItemLayout from './ItemLayout';
@Form.create()
class MyTestForm extends React.Component {
render() {
const { form } = this.props;
return(
<Form>
{
formConfig().map((item, i) =>
<ItemLayout><BaseItem key={i} config={item} form={form}/></ItemLayout>)
}
</Form>
)
}
}
export default MyTestForm;
Compared to traditional structures Form is not fast a lot, and page code level even more clearer.
note:
If you want to use a custom component (a personalized business component), the simple point I package for the Input
//自动trim的Input
import { Component } from 'react';
import { Input } from 'antd';
class TrimInput extends Component {
handleChange = (e) => {
e.target.value = e.target.value.trim();
this.props.onChange(e.target.value); //Input Chang 后将值传递给props
}
render() {
const { value, ...argv } = this.props;
return(
<Input
value={ value } //将props的填在Input中
{ ...argv }
onChange={this.handleChange}/>
)
}
}
export default TrimInput;
Business component needs to have the ability to customize the way data flows, the most important point is that when updates need to call
this.props.onChange(data)
.
Search Form package SearchForm
( )
If you feel this is not enough fun, then come together on BaseItem
to re-package the business component of it. I believe everyone has a background search capabilities of it, then we packed a search SearchForm
.
The increase is mainly a search
function of the value and pass out of form.
The main code is as follows:
//searchForm.js
import React from 'react';
import { Form, Button } from 'antd';
import BaseItem from './BaseItem';
import ItemLayout from './ItemLayout';
@Form.create()
class SearchForm extends React.Component {
handleSearch = () => {
const { form: { validateFields }, search } = this.props;
validateFields((err, fieldsValue) => {
console.log(fieldsValue);
if(!err) {
search && search(fieldsValue);
}
})
}
render() {
const { form, searchConfig, search, form: { resetFields } } = this.props;
return(
<>
<Form onSubmit={this.handleSearch}>
{
searchConfig().map((item, i) =>
<ItemLayout><BaseItem key={i} config={item} form={form}/></ItemLayout>)
}
{
search && <div>
<Button htmlType="submit" type="primary" style={{marginRight: '20px'}}>
搜索
</Button>
<Button onClick={() => resetFields()}>重置</Button>
</div>
}
</Form>
</>
)
}
}
export default SearchForm;
Use the inside pages, single table or pumped into the profile uses:
//config.js 查询条件
export const searchConfig = () => {
return [
{
itemOptions : {
label: '条件一'
},
name: 'name1',
initialValue: '',
rules: [],
children: <Input />
},
{
itemOptions : {
label: '条件二'
},
name: 'name2',
initialValue: '',
rules: [],
children: <Input />
}
]
}
import React from 'react';
import { searchConfig } from './config';
import SearchForm from './SearchForm';
class MyTestForm extends React.Component {
handleSearch = value => {
console.log(value);//获取到的查询条件
}
render() {
return(
<SearchForm searchConfig={searchConfig} search={this.handleSearch} />
)
}
}
export default MyTestForm;
Write queries like this form is not very fast Yeah, interrogated later on referring to this component, and then draw a profile, so OK.
Modal + Form
There will often encounter this situation, pop inside Form
, like this you need to pop to increase the capacity to collect data. We put the equivalent searchForm
of components on Modal inside. Specific implementation code is not posted.
antd Form
Several problems need attention.
initialValue
This property is just set the form of the initial value, when the need to dynamically change the value of the form of the time, usesetFieldsValue
resetFields
This property is a set of values and the reset state of the control input, (reset valueinitialValue
, instead of clearing the data, the data needs to be emptied or usedsetFieldsValue
)
antd Form
New changes
antd Form
In the fourth version rc-field-form
, but has not yet released, I saw on the 4.0-prepare branch.
There are two underlying components so what difference does it make?
First rc-field-form
will try to api
be consistent on the level, but there are still places made changes. Mainly the following points:
When not manually updated forms, we will not collect
initialValues
valueIn
rc-form
which, if the user does not operate through a form, you will form from theinitialValues
collection value. They think it's a bug, but a lot of users are using this, so they do not do repairs. In therc-field-form
middle, you will not have this bug. If you want to change the value of components usedsetFieldsValue
instead.Instead of using an array of nested name string
rc-form
Inside supportuser.name
will eventually be interpreted as{user:{ name: '' } }
rc-field-form
It would be['user', 'name']
interpreted as{user: { name: '' }}
and willuser.name
explain to become{ ['user.name']: ''}
Delete
validateFieldsAndScroll
this propertyBecause of the use
findDomNode
, butfindDomNode
in theStrictMode
middle it is marked as a warning. I think this is a form of excessive control components.getFieldsError
We will always return to the arrayrc-form
When there is no wrong, it returns null,rc-field-form
and now returns an empty arrayDelete the
validateFields
callback functionBecause of
ES8
supportasync/await
, there is no reason not to use it. When we use should beasync function() { try { const values = await form.validateFields(); console.log(values); } catch (errorList) { errorList.forEach(({ name, errors }) => { // Do something... }); } }
setFields
Will not triggeronFieldsChange
andsetFieldsValue
do not triggeronValuesChange
to sum up
This article is written own background most Form summary, as well as provide a way for everyone, the background of the rapid development of the way.
Will be updated later antd other components, how is the development of components more suitable for business scenes.