受控组件与非受控组件:是否受状态控制。
1.用受控组件实现双向数据绑定
我们来实现一个react的双向数据绑定
让输入框输入值,下面的显示跟着变化
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
class Input extends Component{
constructor(){
super();
this.state={val:''}
}
render(){
return (<div>
<input type="text" value={this.state.val}/>
{this.state.val}
</div>)
}
}
ReactDOM.render(<Input/>, document.querySelector('#root'));
但是结果和我们想象的不一样:输入框不能输入值。这是因为input的value取的是state中的val。但是val的值一直是空。 改变state的唯一方式setState
- 受状态控制的组件,必须要有onChange方法,否则不能使用.
- 受控组件可以赋予默认值(官方推荐使用受控组件)
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
class Input extends Component{
constructor(){
super();
this.state={val:'100'}
}
handleChange=(e)=>{//e是事件源
let val=e.target.value;
this.setState({val});
}
render(){
return (<div>
<input type="text" value={this.state.val} onChange={this.handleChange}/>
{this.state.val}
</div>)
}
}
ReactDOM.render(<Input/>, document.querySelector('#root'));
简单功能实现,输入框值,与显示值统一。这就是受控组件,受状态控制。
2.受控组件公用方法的状态控制
两个输入框实现求和功能,如果使用两个onchange事件,会造成代码的冗余。我们现在把他们合在一起。
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
class Sum extends Component{
constructor(){
super();
this.state={a:1,b:1}
}
//key表示的当前状态改的是哪一个
//e表示的是事件源
handleChange=(key,e)=>{//处理多个输入框的值映射到状态的方法
let val=e.target.value;
this.setState({[key]:val});
}
render(){
return (<div>
<input type="text" value={this.state.a} onChange={(e)=>{
this.handleChange('a',e)
}}/>
<input type="text" value={this.state.b} onChange={(e)=>{
this.handleChange('b',e)
}}/>
{this.state.a+this.state.b}
</div>)
}
}
ReactDOM.render(<Sum/>, document.querySelector('#root'));
这样就可以通过一个方法实现两个onchange事件的功能,不过上面是两个字符串的拼接,需要转为数字再相加,在这就不做了。
3.非受控组件(不受状态控制)
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
//输入框value值不受状态控制,不能初始化默认值
class Sum extends Component{
constructor(){
super();
this.state={result:''}
}
//通过ref设置的属性,可以通过this.refs获取到对应的dom元素
handleChange=()=>{
let result=this.refs.a.value+this.refs.b.value;
this.setState({result});
}
render(){
return (<div onChange={this.handleChange}>//运用冒泡的机制不在两个input中添加onchange事件
<input type="text" ref="a"/>
<input type="text" ref="b"/>
{this.state.result}
</div>)
}
}
ReactDOM.render(<Sum/>, document.querySelector('#root'));
上面这种实现方式,两个输入框不受状态的控制。通过操作dom获取到value值,然后进行相加。这就是非受控组件,他与受控组件的区别就是不可以给默认值。
ref的另外一种实现方式(推荐)
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import ErrorBoundary from './components/ErrorBoundary';
import Counter from "./components/Counter";
import Todos from "./components/Todos";
//输入框value值不受状态控制,不能初始化默认值
class Sum extends Component{
constructor(){
super();
this.state={result:''}
}
//通过ref设置的属性,可以通过this.refs获取到对应的dom元素
handleChange=()=>{
let result=this.refs.a.value+this.b.value;
this.setState({result});
}
render(){
return (<div onChange={this.handleChange}>//运用冒泡的机制不在两个input中添加onchange事件
<input type="text" ref="a"/>
//x代表真实的dom ,把元素挂载到了当前实例上
<input type="text" ref={x=>this.b=x}/>
{this.state.result}
</div>)
}
}
ReactDOM.render(<Sum/>, document.querySelector('#root'));
第二个输入框中ref给了一个箭头函数,x代表真实的dom,把真实dom赋值给当前实例中。