1,什么是状态提升?
在很多情况下我们在React组件中 数据并不一定只是在组件内部使用,我们有可能需要将组件中的数据共享出来,在其他组件中使用。但之前我们说过React是一个单向数据流,只能将数据通过props传入子组件中,子组件中也只能将数据通过state在组件内部流动,或者再通过props传入到该组件的子组件中,类似于瀑布一样,数据向下流动,中间可能会产生数据但仍只能向下流。而此时我们就需要将组件中的数据共享到兄弟组件或者父组件该怎么办,所以本章要讲的是状态提升,通过本章节我们将会实现。
举例:现在我们有一个需求,实现一个温度计,输入温度后,根据温度判断是否水进行沸腾。。现在代码如下:
import React from 'react';
import ReactDOM from 'react-dom';
class ShowPanel extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
水:{this.props.ht >= 100 ? "沸腾了" : "没有沸腾"}
</div>
);
}
}
class Hinput extends React.Component{
constructor(props){
super(props);
this.state={ht:0};
}
onChange = (e) =>{
this.setState({
ht:e.target.value
});
}
render(){
return (
<div>
华氏温度:<input type="text" value={this.state.ht} onChange={this.onChange.bind(this)}/>
<br/>
<ShowPanel ht={this.state.ht}/>
</div>
);
}
}
//使用大括号中进行遍历
ReactDOM.render(<Hinput />,document.getElementById('root'));
上面代码为一个输入框以及内嵌一个显示面板组件。现在我们需求是希望有一个计算器有两个输入框分别为华氏度和摄氏度都可以进行输入,并且两个输入框中数据同步显示换算,现我们分析后 觉得需要有两个输入组件和一个显示面板 以及组装成的计算器组件,页面直接引用计算器组件。代码如下:
import React from 'react';
import ReactDOM from 'react-dom';
class ShowPanel extends React.Component{
constructor(props){
super(props);
}
render(){
var degrees = this.props.degrees;
return (
<div>
水:{degrees >= 100 ? "沸腾了" : "没有沸腾"}
</div>
);
}
}
class Cinput extends React.Component{
constructor(props){
super(props);
}
onChange = (e) =>{
this.props.onChange(e.target.value);
}
render(){
return (
<div>
摄氏温度:<input type="text" value={this.props.cdegrees} onChange={this.onChange.bind(this)}/>
<br/>
</div>
);
}
}
class Finput extends React.Component{
constructor(props){
super(props);
}
onChange = (e) =>{
this.props.onChange(e.target.value);
}
render(){
return (
<div>
华氏温度:<input type="text" value={this.props.fdegrees} onChange={this.onChange.bind(this)}/>
<br/>
</div>
);
}
}
//温度计
class TemperatureComputer extends React.Component{
constructor(props){
super(props);
this.state={cdegrees:0,fdegrees:0,type:'c'};
}
toCelsius = (fahrenheit) => {
return (fahrenheit - 32) * 5 / 9;
}
toFahrenheit = (celsius) => {
return (celsius * 9 / 5) + 32;
}
onCinputChange = (cval)=>{
var fval = this.toFahrenheit(cval);
this.setState(()=>{
return {cdegrees:cval,fdegrees:fval,type:'c'};
});
}
onFinputChange = (fval)=>{
var cval = this.toCelsius(fval);
this.setState(()=>{
return {fdegrees:fval,cdegrees:cval,type:'f'};
});
}
render(){
return (
<div>
<Cinput cdegrees={this.state.cdegrees} onChange={this.onCinputChange.bind(this)}/>
<Finput fdegrees={this.state.fdegrees} onChange={this.onFinputChange.bind(this)}/>
<ShowPanel degrees={this.state.cdegrees} />
</div>
);
}
}
ReactDOM.render(<TemperatureComputer />,document.getElementById('root'));
总结:通过上面代码我们可以看出 比较关键的地方就是我们在输入组件上添加了一个onChange事件,并且在输入组件内部我们在组件内输入发生变化时,通过组件内部监听函数,调用了该组件属性中的onChange事件,故而触发了该组件对外暴露的onChange属性函数(组件的onChange 命名不一定必须要用“onChange” 这里命名只是为了养成一个好的习惯而已,因为大部分组件的内容改变函数均命名为onChange),然后在组件的onChange函数中 调用父组件中的监听函数,从而操纵了父组件state 进而触发改变了该组件的兄弟节点组件。从而达到了组件内部数据向上的“逆向传递”。也称作为状态提升。