什么是受控组件和非受控组件
首先举个栗子:
这两个组件的功能和表现是一模一样的,但是根据其对表单值的控制行为,我们将其区分为受控组件和非受控组件两种。下面是官网对受控组件和非受控组件的介绍和定义:
We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.
受控组件:也被称做“受限组件”或“受约束组件”。其所有状态属性的更改都由React 来控制,即它根据组件的props和state来改变组件的UI表现形式。
非受控组件:不受React 的状态控制(state或props)。(非受控组件是在底层实现时内部维护了自己的状态state,这样表现出用户输入任何值都能反应到元素上。)
交互流程图如下:
两种组件比较
React 认为:组件应当只受状态的改变而改变,虽然使用受控组件在代码量上有所增加,但推荐使用受控组件。受控组件的组件状态由React 控制,可以更好的控制数据流,在用户输入时能够更新组件状态。
受控组件的优势:
1、更符合React组件状态控制UI的思想。
2、外部props可以实时控制组件state,进而同步UI数据。
3、可以非常容易实现对用户输入的验证,或者对用户交互做额外的处理。
通过onChange方法来实现监控控制。当然,非受控组件也可以使用onChange,但是如果使用的话就不如直接做成受控组件了,代码量的优势也没有了
那非受控组件真的就没有什么意义了吗?当然不是。对无需外部控制且无复杂交互的表单往往可以使用非受控组件。例如antd的Tree组件,当有非常多的节点时,对TreeNode进行控制就不是很明智。Tree组件本身可以实现结果的保存获取,而再使用受控的方式则必须在每次变化时转换为输出格式,在控制变量变化时再转换为内部计算格式。如果转换过程比较耗时就会感到卡顿。(非受控组件内部可能由很多受控组件组成,受控组件和非受控组件组合实现React界面,两者缺一不可)
受控组件和非受控组件的属性对比如下:
对比内容 | 受控组件 | 非受控组件 |
---|---|---|
value/checked | 设置 | 不设置 |
onChange | 可使用 | 可使用 |
defaultValue/defaultChecked | 不起作用 | 可使用 |
ref | 没有必要 | 可使用 |
其他 | 可使用 | 可使用 |
受控组件用法整理
1、根据上面思路,整理受控组件数据流控制流程图如下:
2、多表单元素可共享事件处理器
在创建表单组件时,有时多个组件的事件处理器功能相同或相似,这时我们可以在多个组件间共享一个事件处理器,而不用分别编写事件处理器。共享事件处理器时,需要解决参数传递的问题。
a. 传参:事件监控函数传参区别组件,这里注意需要绑定this。(常用)
b. 通过底层DOMname属性区分:
12345 handleChange: function(event) {var newState = {};newState[event.target.name] = event.target.value;this.setState(newState);}c. 通过React addon的LinkedStateMixin方法实现共享(已经被React v15.5.抛弃,请转上面)
ANTD Form组件
项目中常会用到ANTD的FORM组件来实现复杂表单。Input等Data Entry表单元素组合出现在FormItem中,共同组成了Form表单。然而我们发现,我们往往并没有使用state或者props控制单个表单元素的value,而是使用了ANTD Form组件提供的getFieldDecorator方法注册监听各个表单元素。ANTD提供了一套API来控制表单元素,使用的是非受控的组件方法。
从ANTD Form组件官方示例和API介绍可以知道,ANTD Form组件实现了对表单元素的实时校验、获取设置值、UI扩展等功能。下面一段话摘自官网:
经过 getFieldDecorator 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:
1、你不再需要也不应该用 onChange 来做同步,但还是可以继续监听 onChange 等事件。
2、你不能用控件的 value defaultValue 等属性来设置表单域的值,默认值可以用 getFieldDecorator 里的 initialValue。
3、你不应该用 setState,可以使用 this.props.form.setFieldsValue 来动态改变表单值。
举个简单的例子:
看下源码:
由源码可以看出,ANTD Form表单的确是用的非受控方式实现了对表单元素的控制,当然由于函数方法封装覆盖了表单元素的属性,所以ANTD官方也不建议在使用Form组件时使用value和defaultValue来直接控制表单元素(你可能会发现即使设置了也会失效,因为从源码可以看出,对表单元素属性进行了覆盖合并)。
受控组件和非受控组件在react的使用中非常普遍,互相嵌套。Form表单如何更高效的使用,欢迎后续继续研究讨论。