概述
React规则规定,state只能被拥有它的组件修改。
如果有几个组件需要同步state该如何处理?
即,其中一个组件更改state,其它组件state保持同步,反之亦然。
要保持state同步,各组件必须拥有共同的“数据源”,当一个组件的state发生变化,将其state的值提高到各组件最近共同的父组件中,然后由父组件统一传递给各组件,其它组件亦然。
state只能由拥有它的组件改变,那么子组件又是如何使父组件的state改变呢?
==父组件创建一个改变state函数;
==将该函数作为props的属性传递到子组件;
==子组件调用该函数使父组件的state改变;
完美!
记住,数据自定往下流。
我现在要做个小程序,两个输入框,一个输入人民币,一个输入美元,当输入人民币时,美元输入框显示人民币转换后的美元,当输入美元时,人民币输入框显示美元转换后的人民币。
且看如何实现。
创建Money类组件
/**
* Money组件
*/
class Money extends Component{
constructor(props){
super(props);
//
}
render(){
return(
<div>
<input type="text" />
</div>
);
}
}
用来渲染输入框的。
创建汇率类组件
ExchangeRate组件2次渲染Money组件,一次表示人民币,一次表示美元
/**
* 汇率组件
*/
class ExchangeRate extends Component{
constructor(props){
super(props);
//
}
render(){
return(
<div>
<Money />
<Money />
</div>
);
}
}
创建Money标志
const MoneyTag = {
Y: 'CNY',
D: 'Dollar'
}
Y表示人民币
D表示美元
并在ExchageRate组件中初始化state
this.state = {
tag: 'Y',
num: ''
}
tag:类型,默认人民币
num:输入的金额,默认为空
创建汇率转换函数
/**
* 美元转换成人民币
* @param {*} num
*/
to_cny(num){
return num * 6.6392;
}
/**
* 人民币转换成美元
* @param {*} num
*/
to_dollar(num){
return num * 0.1506;
}
/**
* 汇率转换
* @param {*} tag
* @param {*} num
*/
exchange_rate_change(tag,num){
const input = parseFloat(num);
if(Number.isNaN(input)){
return '';
}
// 转换成美元
if(tag === 'Y'){
return Math.round(this.to_dollar(input) * 1000000) / 1000000;
}
// 转换成人民币
return Math.round(this.to_cny(input) * 1000000) / 1000000;;
}
输入的是人民币,则需要转换成美元;
输入的是美元,则需要转换成人民币;
将参数专递给子组件
render(){
const tag = this.state.tag;
const num = this.state.num;
const cny = tag === 'Y' ? num : this.exchange_rate_change(tag,num);
const dollar = tag === 'D' ? num : this.exchange_rate_change(tag,num);
return(
<div>
<Money tag='Y' num={cny} />
<Money tag='D' num={dollar} />
</div>
);
}
子组件获取参数并展示
<input type="text" value={this.props.num} />
汇率(ExchangeRate)组件添加状态改变函数
/**
* 改变状态
* @param {*} tag
* @param {*} num
*/
handle_change(tag,num){
this.setState({
tag: tag,
num: num
});
}
如果要使用this.setState这个方法,就需要绑定this,因为如果不绑定,那么this.setState中的this指的是handle_change这个方法,显然该方法并没有setState这个方法,故而会报错。当然,也可以使用箭头函数(后面再讲)。
绑定this:
constructor(props){
super(props);
this.state = {
tag: 'Y',
num: ''
}
// 绑定this
this.handle_change = this.handle_change.bind(this);
}
此时handle_change中的this指的就是对象(ExchangeRate)本身了。
状态函数要像属性一样,通过props传递给子组件:
<div>
<Money tag='Y' num={cny} handle_change={this.handle_change} />
<Money tag='D' num={dollar} handle_change={this.handle_change} />
</div>
子组件(Moeny)添加onChange函数
监听输入框的变化,并调用父组件传递过来的handle_change函数,使父组件的state改变:
/**
* Money组件
*/
class Money extends Component{
constructor(props){
super(props);
//
}
/**
* 输入金额切换状态
* @param {*} e
*/
handle_change(e){
this.props.handle_change(this.props.tag,e.target.value);
}
render(){
return(
<div>
<input type="text" value={this.props.num} onChange={(e) => {
this.handle_change(e);
}} />
</div>
);
}
}
此时,
你在人民币输入框输入金额,美元输入框就会自动兑换;
你在美元输入框输入金额,人民币输入框就会自动兑换;
添加金额符号
为了便于区别,需在输入框后面添加金额符号
render(){
const symbol = this.props.tag === 'Y' ? "Y" : "$";
return(
<div>
<input type="text" value={this.props.num} onChange={(e) => {
this.handle_change(e);
}} />{symbol}
</div>
);
}
为了简化,暂用“Y”替代人民币符号
效果展示
Paste_Image.png完整代码
const MoneyTag = {
Y: 'CNY',
D: 'Dollar'
}
/**
* Money组件
*/
class Money extends Component{
constructor(props){
super(props);
//
}
/**
* 输入金额切换状态
* @param {*} e
*/
handle_change(e){
this.props.handle_change(this.props.tag,e.target.value);
}
render(){
const symbol = this.props.tag === 'Y' ? "Y" : "$";
return(
<div>
<input type="text" value={this.props.num} onChange={(e) => {
this.handle_change(e);
}} />{symbol}
</div>
);
}
}
/**
* 汇率组件
*/
class ExchangeRate extends Component{
constructor(props){
super(props);
this.state = {
tag: 'Y',
num: ''
}
// 绑定this
this.handle_change = this.handle_change.bind(this);
}
/**
* 美元转换成人民币
* @param {*} num
*/
to_cny(num){
return num * 6.6392;
}
/**
* 人民币转换成美元
* @param {*} num
*/
to_dollar(num){
return num * 0.1506;
}
/**
* 汇率转换
* @param {*} tag
* @param {*} num
*/
exchange_rate_change(tag,num){
const input = parseFloat(num);
if(Number.isNaN(input)){
return '';
}
// 转换成美元
if(tag === 'Y'){
return Math.round(this.to_dollar(input) * 1000000) / 1000000;
}
// 转换成人民币
return Math.round(this.to_cny(input) * 1000000) / 1000000;;
}
/**
* 改变状态
* @param {*} tag
* @param {*} num
*/
handle_change(tag,num){
this.setState({
tag: tag,
num: num
});
}
render(){
const tag = this.state.tag;
const num = this.state.num;
const cny = tag === 'Y' ? num : this.exchange_rate_change(tag,num);
const dollar = tag === 'D' ? num : this.exchange_rate_change(tag,num);
return(
<div>
<Money tag='Y' num={cny} handle_change={this.handle_change} />
<Money tag='D' num={dollar} handle_change={this.handle_change} />
</div>
);
}
}
const element = (
<div>
<ExchangeRate />
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
注:
本教程相关的所以源码,可在https://github.com/areawen2GHub/reacttest.git下载
参考地址:
https://react.bootcss.com/react/docs/lifting-state-up.html
网友评论