前言
最近在用React做项目,因为内容主要是增伤改查,就决定选择一个可以方便做增删改查的框架,经同事推荐,选择了ant-design。
但是在开发过程中遇到了各种困惑,一方面是因为对react本身的不熟悉,另一方面则是对ant-design框架的不熟。
因为业务重点在于表单的增删改查,自然是从form表单开始捣鼓。
正文
antd-form的初始感觉
第一次看antd-form文档时,只是感觉头皮发麻,因为用vue写同样的东西,几行就可以搞定,用react确实要几十行,就觉得,用react做东西太费劲了。不过既然已经准备好跨越React这道坎,闲话不多说,学习就完了。
React相关知识概要
因为本章节重点是讨论ant-form的工作流程,所以相关基础的东西,只做简单概括。
React本身:
React本质上来说,就是一个前端的状态机,state
的更新带动了view
的更新。
高阶组件
简单理解下,高阶函数通常指一个函数:接受一个函数或者返回一个函数,的函数。
这个概括到高阶组件就是接受一个组件作为参数,返回一个组件的,的函数。嗯。它是一个函数
antd-form
antd-form本身提供一些简单的组件,例如Form,FormItem
,并且提供一些简单的功能,Form组件与FormItem组件相互配合,可以直接拿来写表单的业务逻辑。支持错误提示文本与校验状态,但是大部分的内容需要手动去控制。比如触发错误信息的展示,校验状态的改变,等等。
这种情况是基本满足业务需求的,但是,对于写惯了vue的我来说,对于双向数据绑定有种天生的痴迷,此时不得不去探究该控件更高级的用法,自动验证&反馈
因为antd-form中引用了一个叫做rc-form的组件,并且API中与rc-form有大量的重复,所以如果想了解它的自动验证&反馈,就不得不去学习rc-form。
rc-form
初体验
一个最基本的用法
import React from 'react';
import ReactDOM from 'react-dom';
import { createForm, formShape } from 'rc-form';
class Form extends React.Component {
static propTypes = {
form: formShape,
};
componentWillMount() {
this.nameDecorator = this.props.form.getFieldDecorator('name', {
initialValue: '',
rules: [{
required: true,
message: 'What\'s your name?',
}],
});
}
onSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((error, values) => {
if (!error) {
console.log('ok', values);
} else {
console.log('error', error, values);
}
});
};
onChange = (e) => {
console.log(e.target.value);
}
render() {
const { getFieldError } = this.props.form;
return (
<form onSubmit={this.onSubmit}>
{this.nameDecorator(
<input
onChange={this.onChange}
/>
)}
<div style={{ color: 'red' }}>
{(getFieldError('name') || []).join(', ')}
</div>
<button>Submit</button>
</form>
);
}
}
const WrappedForm = createForm()(Form);
ReactDOM.render(<WrappedForm />, document.getElementById('__react-content'));
体验链接:点我
效果如图:
这个案例是非空校验,初始状态无错误提示,当文本框输入内容再清空时候,显示错误内容;或者初始状态直接提交时也会显示错误内容。
流程剖析
代码最底部创建了一个form,通过语句createForm(configObj)(wrappedComp)
。组件在componentWillMount
时候,通过props.form获得被包装上的方法getFieldDecorator
,这个方法返回一个函数,该函数接受一个待修饰的组件,本例子中是input。render
部分会调用该函数,该函数内部最终会生成一个inputProps
,并在最后通过React.cloneElement(input, {...inputProps})
返回被包装的元素。其中inputProps包含一个内部处理过的onChange事件和一个value属性用来显示文本框的值,作用于该被包装元素input
上,当input输入值时候,则会调用内部的onChange事件,触发getFieldDecorator
中配置的校验规则,校验输入,并在更新结果后,通过this.forceUpdate
方法更新组件,重新触发render,走render内部的流程,这样一来,就形成了所谓的双向数据绑定
。
后续
至此已整理出最基本的demo,但是这只是考虑了最基本的demo。实践中,要考虑到表单的编辑,需要在createForm(configObj)(cmp)
中处理configObj,设置mapPropsToFields
将后台的数据反显到前端页面中去,并且在字段更新后change回props的来源。当然这就涉及到更麻烦的处理,需要根据业务逻辑酌情处理。
未完待续
不得不说为了考虑框架的拓展性以及严谨,有很多代码看起来很费力,但是值得细挖。挖个坑,后续慢慢填吧。
探究过程中的一些额外收获
npm包
import hoistStatics from 'hoist-non-react-statics';
// 作用:常用语高阶组件中,将被包裹元素的静态方法,“同步”到容器元素中。
hoistStatics(Container, WrappedComponent);
import omit from 'omit.js';
// 作用: 从已经存在的对象中过滤特定属性
const formProps = omit(this.props, [
'prefixCls',
'className',
'layout',
'form',
'hideRequiredMark',
]);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。