antd form(rc-form) vs redux-form vs react-final-form

antd form react-final-form redux-form
customize Field yes yes yes
asyncValidating yes yes yes
form create HOC Context Context, HOC
react 16 yes yes yes
Form state management “state” “state” redux
Field state management “state” “state” redux
has basic component yes false false
Array getFieldDecorator (`names[${k}]`, {…})() 同 redux-form <Field name={`${member}.firstName`} />
value deliver from values N/A Pub/Sub mapStateProps
get values this.props.form. getFieldsValue((value) => {}) onSubmit(values) onSubmit(values)
Performance reconciler other field reconciler other field reconciler other field but scu
Field getFieldDecorator (name, {}) <Field /> <Field />

写法

由于要给 Form 赋上很多功能,antd form 和 redux-form 采用的是 HOC,HOC 看起不太直观,并且多一个步骤。相对于通过 Context 方式少了一点优雅。

redux-form 在使用了 HOC 的同时还使用了 Context,混合的使用方式,吸取了 HOC 的 proxy props 的长处为 Field 赋上 onChange 等事件。

antd from 借助 API getFieldDecorator() 来实现表单元素的“双向绑定”略显繁琐。

性能

一下结论都是基于 debug 得出的。

antd from 行为类似于 react-final-form

react-final-form。一个表单元素的改动会触发同一个 form 内的其他表单元素更新,浪费性能

redux-form 由于是通过表单元素自己来管理 state 只有在失去焦点的时候才触发整个 form 表单的更新

实现重用

form 元素有大量需要重用的逻辑

1,数据更新,状态管理,“双向绑定”
2,数据校验,正则,异步,限制输入,错误提示
3,onChange 事件
4,format

那么三大 form 组件库是怎样实现重用的呢?

基本思路是在展现元素外层包一层组件,所有逻辑都在外层组件实现。

react 实现重用的方式有 HOC,render props 和 mixin。 当然 mixin 已经不推荐了。

以上方法都是解决横切关注点的问题。下面介绍下HOC,render props 由于 mixin 官方已经不推荐了,有兴趣的同学可以看看 Mixins Considered Harmful

HOC

1
2
3
4
5
6
7
8
9
10
11
12
function HOCKPIGrid(WrappedComponent) {
return class extends React.Component {
render () {
return (
<WrappedComponent
{...this.props}
{...newProps}
/>
);
}
}
}

HOC 能带来

1,相同的生命周期函数。处理例如挂载监听与卸载时卸载监听。
2,props 相同的处理逻辑,这正是表单元素需要的。

在使用 HOC 不建议改变原始组件,所以输入提示就不适合用这种方式来做。

render props

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Field extends React.Component {
render () {
const {
render,
component,
children,
...rest
} = this.props;
if (component) {
return React.createElement(component, componentProps, children);
}
if (render) {
return render(inlineProps);
}
if (typeof children === 'function') {
return children(inlineProps);
}
return children;
}
}

可以看到 render props 支持三种渲染方式,但是目的都只有一个处理 props。render props 能带来

1,与 HOC 一样, props 相同的处理逻辑
2,动态 children

以上两种方式虽然分开介绍,但是它们时可以组合使用的。

自定义表单元素

antd from: getFieldDecorator()(CustomizeComponent)
CustomizeComponent 里面需要调用 this.props.onChange(value)

react-final-form:

  1. children
    (props) => {};

  2. render
    (props) => {};

  3. component
    creactElement(component);

需要调用 props.input.onChange(value)

redux-form: creactElement(component);
也需要调用 props.input.onChange(value)

function as children 每次父组件有更新,都会导致子元素的重新创建。导致性能浪费。但是这样满足强的单向数据流,不用关心组件状态更新的问题,cwrp 这个坑也就成功避免了。

这里发现没有一个 form 框架使用正常的 props.children 做为子组件,为什么呢?

参考 http://slides.com/jiannian/deck-1

antd

antd-form

react form, react final form

react-form

redux form

redux-form