从入门的角度来聊一下React 的状态提升。
我们先来看一下React官网是怎么介绍这一概念的:
使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。
很简单的一句介绍,由此我们可以很清楚的明白React状态提升主要就是用来处理父组件和子组件的数据传递的;他可以让我们的数据流动的形式是自顶向下单向流动的,所有组件的数据都是来自于他们的父辈组件,也都是由父辈组件来统一存储和修改,再传入子组件当中。
举个栗子
现在我们需要实现一个统计总价的功能:
1、首先,先写一个父组件:class Category extends React.Component { constructor(props){super(props);this.state = {name: "React.JS"}}render(){return <h1>{this.state.name}</h1>}
}
ReactDOM.render(<Category />,document.getElementById('app')
)复制代码
// 子组件
class Children extends React.Component {constructor(props){super(props);}render(){return(<div><label>{this.props.num}<input value={this.props.num} /><button>+</button></label></div>)}
}
// 父组件
class Category extends React.Component {constructor(props){super(props);this.state = {name: "React.JS",num1: 0}}render(){return(<div><h2>{this.state.num1}</h2><Children num={this.state.num1} /></div>)}
}复制代码
现在我们可以看到,Children这个子组件的数据是从父组件传下来,通过this.props拿到 的,但是现在还不能在子组件上面去修改父组件的数据,所以我们的子组件的数据也无 法得到改变。
3、现在我们在子组件里面定义属性,来触发父组件的事件:class Children extends React.Component {constructor(props){super(props);}// input输入框事件setNum(e){this.props.setNum(e.target.value)}// 按钮递增事件addNum(){this.props.addNum()}render(){return(<div><label>{this.props.num}<input onChange={(e)=>this.setNum(e)} value={this.props.num} /><button onClick={()=>this.addNum()}>+</button></label></div>)}
}
class Category extends React.Component {constructor(props){super(props);this.state = {name: "React.JS",// 将子组件的需要用到的数据存放在父组件内,在子组件内通过this.props可以取到num1: 0}}// 处理子组件传上来触发input输入框的处理事件setNum(e){this.setState({num1: parseInt(e)})}// 处理子组件传上来触发button按钮的处理事件addNum(){this.setState({num1: this.state.num1 += 1})}render(){return(<div><h2>{this.state.num1}</h2>// 子组件通过this.props可以触发对应绑定的事件来修改自身的数据<Children addNum={()=>this.addNum()} setNum={(e)=>this.setNum(e)} num={this.state.num1} /></div>)}
}复制代码
到这一步,功能已经实现了,子组件通过this.props去拿父组件的数据,并可以触发属性上面绑定的对应函数来修改父组件的数据,使子组件的数据得到更新;
其实可以看出,Children这个组件的数据不是独立的,而是来自Category组件传下来的,所以,这个Children组件是可以随意复用的,只需要在他的父组件Category上为他存放一个给她传递数据的变量就OK了。
1、首先,我们在Category类的构造函数里的this.state内添加一个新的变量来处理我们即将新 增的另一个子组件:
constructor(props){super(props);this.state = {name: "React.JS",num1: 0,// 添加一个用来处理新组件数据的变量num2: 0 <==================================================}
}复制代码
2、然后在Category组件里我们再写一个新的Children组件,属性上面绑定的数据全部换成们 刚才定义的新变量:
render(){return(<div><h2>{this.state.num1}</h2><Children addNum={()=>this.addNum()} setNum={(e)=>this.setNum(e)} num={this.state.num1} /><Children num={this.state.num2} /></div>)
}复制代码
3、给他绑定属性事件来修改处理他的变量:
class Category extends React.Component {constructor(props){super(props);this.state = {name: "React.JS",num1: 0,num2: 0}}
// 处理num1数据的子组件setNum(e){this.setState({num1: parseInt(e)})}addNum(){this.setState({num1: this.state.num1 += 1})}
// 处理num2数据的子组件newSetNum(e){this.setState({num2: parseInt(e)})}newAddNum(){this.setState({num2: this.state.num2 += 1})}render(){return(<div>// 这里接收两个组件的数据总和<h2>{this.state.num1 + this.state.num2}</h2><Children addNum={()=>this.addNum()} setNum={(e)=>this.setNum(e)} num={this.state.num1} />// 在属性上面绑定新的事件来处理该组件的事件<Children addNum={()=>this.newAddNum()} setNum={(e)=>this.newSetNum(e)} num={this.state.num2} /></div>)}
}复制代码
现在,看一下实际效果:
*总结:
所以,React的状态提升,其实是为了组件之间的数据更加单向性,在数据的传输上始终只会出现一对一的情况,在处理上,也方便我们只需要在向子组件传递数据的那个父辈组件上进行操作,并传回子组件,使得数据更新,这种方法也体现了React的单向数据流的设计思想,在复用组件的时候,组件的数据也不会相互干扰,使代码逻辑上会更加便于管理。