React里受控与非受控组件
背景:
React内部分别使用了props, state来区分组件的属性和状态。props用来定义组件外部传进来的属性, 属于那种经过外部定义之后, 组件内部就无法改变。
而state维持组件内部的状态更新和变化, 组件渲染出来后响应用户的一些操作,更新组件的一些状态。如果组件内部状态不需要更新,即没有调用过this.setState,
全部通过props来渲染也是没问题的, 不过这种情况不常见。本文所介绍的内容就是通过props和state的定义来谈谈React的受控组件和非受控组件。
主体:
非受控组件
顾名思义, 非受控组件即组件的状态改变不受控制.接来下我们以一个简单input组件代码来描述。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Demo1 extends Component {
render() {
return (
<input />
)
}
}
ReactDOM.render(<Demo1/>, document.getElementById('content'))
在这个最简单的输入框组件里,我们并没有干涉input中的value展示,即用户输入的内容都会展示在上面。如果我们通过props给组件设置一个初始默认值,<input defaultValue={this.props.value}/>
defaultValue属性是React内部实现的一个属性,目的类似于input的placeholder属性。
ps: 此处如果使用value代替defaultValue,会发现输入框的值无法改变。
受控组件
上面提到过,既然通过设置input的value属性, 无法改变输入框值,那么我们把它和state结合在一起,再绑定onChange事件,实时更新value值就行了。
class Demo1 extends Component {
constructor(props) {
super(props);
this.state = {
value: props.value
}
}
handleChange(e) {
this.setState({
value: e.target.value
})
}
render() {
return (
<input value={this.state.value} onChange={e => this.handleChange(e)}/>
)
}
}
这就是最简单的受控组件模型, 我们可以通过在onChange的回调里控制input要显示的值,例如我们设置input框只能输入数字
this.setState({
value: e.target.value.replace(/\D/g, '')
})
现在我们应该完全明白form表单中受控组件和非受控组件的关系。受控组件采取的理念类似于redux的单项数据流理念,即value值是在调用者上更新的。
其他参考文章:
React 表单-受控组件与非受控组件
表单是应用中不可缺少的一部分,表单不同于其他 HTML 元素,因为它要响应用户的交互,并根据用户输入显示不同的状态。React 基于props
和state
的组件渲染机制,可以很好的处理表单的复杂性。在React 中,表单组件分为两种:受控组件和非受控组件。
1. 受控组件
1.1 受React控制的值
受控组件也被称做“受限组件”或“受约束组件”。受控组件与其它React组件行为一样,其所有状态属性的更改都由React 来控制,也就是说它根据组件的props
和state
来改变组件的UI表现形式。
对于一个<input>
受限组件,当我们设置其value
值。组件渲染后,其value
值会始终保持不变:
var MyInput = React.createClass({ render: function() { return <input type="text" value="itbilu.com" />; } }); ReactDOM.render( <MyInput />, document.getElementById('example') );
上面的代码渲染后是一个值为itbilu.com
的 input 元素,用户在渲染后的元素里中输入任何值都不起作用,这是因为其值是受React 控制的,React已经为其赋值为itbilu.com
。
1.2 表单组件事件
React控制受控组件
的值保持不变,同样其也会受组件状态的改变,其表现形式和普通React组件一样。而果想响应更新用户输入的值,可以使用React 组件事件设置状态(state
或props
)。
如,我们通过组件的 onChange 事件改变input的value
:
var MyInput = React.createClass({ getInitialState: function() { return {value: 'itbilu.com'}; }, handleChange: function(event) { this.setState({value: event.target.value}); }, render: function() { return <input type="text" value={this.state.value} onChange={this.handleChange} />; } }); ReactDOM.render( <MyInput />, document.getElementById('example') );
1.3 受控组件的好处
受控组件
的优势在于,我们可以非常容易实现对用户输入的验证,或者对用户交互做额外的处理。
如,对用户输入做截断处理:
handleChange: function(event) { this.setState({value: event.target.value.substr(0, 140)}); }
上面的代码会接受用户输入,并截取前 140 个字符
2. 非受控组件
2.1 反模式
非受控组件
相对于普通React 组件或受控组件
来说是一种反模式。非受控组件
不受React 的状态控制(state
或props
)。
如,对于<input>
来说,当我们不设置其value
或设置为null
时就是一个非受控组件
。非受控的组件
渲染出来的元素直接反应用户输入,其值会随用户输入的改变而改变:
var MyInput = React.createClass({ render: function() { return <input type="text" />; } }); ReactDOM.render( <MyInput />, document.getElementById('example') );
非受控组件
依然可以设置初始值。如,我们可以<input>
的defaultValue
属性:
render: function() { return <input type="text" defaultValue="itbilu.com" />; }
2.2 非受控组件的事件
和受控组件一样,非受控组件
同样可以使用React 组件事件。
如,我们可监听<input>
的onChange
事件:
var MyInput = React.createClass({ handleChange: function(event) { this.setState({value: event.target.value}); }, render: function() { return <input type="text" defaultValue="itbilu.com" onChange={this.handleChange} />; } }); ReactDOM.render( <MyInput />, document.getElementById('example') );
2.3 非受控组件的引用
非受控组件
一般没什么用途,其值并非受父组件控制,它的值受其自身控制。但是,我们可以对其添加一个ref
属性,这样可以获得对非受控组件
渲染后底层DOM元素的访问。
3. 受控组件与非受控组件的选择
React 组件应当只受状态的改变而改变,虽然使用受控组件
在代码量上有所增加,但推荐使用受控组件
。受控组件的组件状态由React 控制,可以更好的控制数据流,在用户输入时能够更新组件状态。
在前面的<input>
示例中,一个受控组件有如下过程:
- 通过
getInitialState
设置defaultValue <input>
渲染时设置默认值onChange
事件触发后,调用相关处理器change
事件处理更新state
- 重新渲染
<input>
.