react整理(二)组件之间的传值

上一节说到如何在react中创建组件,知道了创建,还得知道怎么使用,这一节来整理react组件之间的传值。

react的核心思想就是组件化,组件之间UI的展示主要通过值的传递。我们可以将组件的定义看成以下的公式:

UI = Component(props, state)

也就是说,组件是根据props,state来定义界面UI的。props是对外的数据,而state是对内的数据。
props与state的区别在于,props数据是不可变的,而state的数据是可变的。

对于props来说,组件里可以引用别的组件,组件之间的引用会构成一个状态树。那么,父级组件可以通过子组件的props来传值,但是这种值的传递是单向的,子组件不被允许更改父级组件的值,若要改变,只能更改在父级组件中更改。这里我们暂且说说,父级组件如何传值给子组件,至于子组件如何主动去更改父级组件,我们在后续详细说明。

通过一个例子来了解父级组件如何向子组件传递数据:
有两个组件,一个是父级组件,我们叫它index,一个组件,我们叫Children。父级组件index引用子组件Children,可通过子组件的Props来传值。

import react, {Component} from 'React';
import Children from 'Children';

export default class Index extends Component{
render(){
	// 向Children传入值
	const  params = {
		sort: 0,
		name: 'lily'
	}
	return (
		<Children  {...params}/>   // es6解构传入
	)
  }
}
import react, {Component} from 'React';

export default class Children extends Component{
render(){
	// 通过props获取到父级传递的值
	const { sort, name } = this.props;
		return (
		<div>{name}</div>
		<div>{sort}</div>
		)
	}
}

除开外部数据,组件自身也需要一个小仓库来存储自身的状态与数据。而state就是用来记录、改变组件内部数据状态。在react里,只需要更新组件的state,然后根据新的state重新渲染用户界面(不要操作DOM)

如何定义的简单例子:

export default class Index extends Component{
// 通过构造函数来初始化state
	construct(props){
		super(props);
		this.state = {
			timeout: new Date();
		}
  	}

	changeTime(){
	// 改变state的值
		this.setState({
			timeout: new Date();
		})
	}

	render(){
		return(
		// 获取timeout的值
			<span>this.state.timeout.toLocalString()</span>
			<Button OnClick={this.changeTime.bind(this)}>改变timeout</Button>
		)
	}
}

现在我们知道了怎样使用state了。那么接下来我们需要知道,如何定义好一个state。
正确创建一个组件的第一步就是定义合适的state,我们不能将组件中所有的值都通过state来保存,造成state的滥用,一是影响代码结构,二会影响性能(一个setState会经历四个生命周期)。

react中state的特点
1.是异步操作的函数
2.组件在还没有渲染之前,this.setState还没有被调用。
3.批量执行State转变时让DOM渲染更快(对比一个个执行state)

state应该能提现以下方面
1.state中的数据应该是能体现出组件UI每一次状态的变化,且是每一个组件UI呈现出来的状态集。
2.state的数据,不应该通过其他状态来计算出中间状态。

所以,在每一次需要在state中定义状态之前,我们都应该去考虑以下几点:
1.我们定义的state中的值是否可以通过上层组件拿到,或者说可以从其他state状态中计算而得,如果是,放弃添加。
2.我们定义的state是否不需要在render方法中执行,如果是,我们可以考虑在组件的全局定义一个普通属性。
3.我们定义的state是否在整个生命周期中都保持不变,如果是,放弃添加。

我们知道了如何正确使用,但还需使用时的注意事项。

使用state我们应该注意哪些事项?
1.state是不可以直接修改的,比如说要修改一条数据,使用如下方式:
this.state.time = new Date();
这种情况是绝不允许的,更改state中的状态必须使用setState()函数。

2.state是异步执行的。
举个例子,假设有一个购物车,当点击一次购买按钮,购买的数量就会加1,如果我们连续点击了两次按钮,就会连续调用两次this.setState({quantity: this.state.quantity + 1}),但是在React中,合并多次修改为一次的情况下,相当于等价执行了如下代码:
Object.assign(
previousState,
{quantity: this.state.quantity + 1},
{quantity: this.state.quantity + 1}
)

后面的操作覆盖掉了前面的操作,最终购买的数量只增加了1个。

我们要明白的是,在react中,setState是异步执行的,会将待改变的状态添加到队列中,比较更新,找到一个特定的时机,执行一次setState()方法。我们在每一次调用setState()这个函数时,数据并不会立马就更新,下面来个错误示范:

changeState(){
	this.setState({ quantity: this.state.quatity});
	this.setState({ quantity: this.state.quatity});
	this.fetchData(this.state.quatity);
}

在刚刚接触state时,我们就会像以上那样写。这里存在两个错误,一是setState()这个函数只会执行一次,而是setState()这个是异步更新的,执行完setState(),作为fetchData的参数并不是立马就更新了。

如果你真的需要实现以下需求。
(1)下一个数据依赖上一个数据,可以使用另一个接收一个函数作为参数的setState,这个函数有两个参数,第一个参数是组件的前一个state(本次组件状态修改成功前的state),第二个参数是组件当前最新的props。

// 错误
changeState(){
	this.setState({ quantity: this.state.quatity});
	this.setState({ quantity: this.state.quatity});
}
// 正确
this.setState((preState, props) => ({
  counter: preState.quantity + 1; 
}))

(2)方法需要依赖state的值
执行的方法需要使用state更新后的值。可以使用es6的写法,当然和第一种情况其实是一样的。将异步变成同步。

// 错误
changeState(){
	this.setState({ quantity: this.state.quatity});
	this.fetchData(this.state.quatity);
}
// 正确
changeState(){
	this.setState({ quantity: this.state.quatity}).then(()=>{
	this.fetchData(this.state.quatity);
});

(3)一个地方有多个地方setState如何优化?
我们在一个方法里,有时间很难去避免要执行多个setState()方法。比如下面这样:

changeOnTab(num){
switch(num){
	case 1:
		this.setState({
		username: mm,
		age: 13,
		})
	break
	case 2:
		this.setState({
			username: dd,
			age: 14,
		})
	break
	case 3:
		this.setState({
			username: dd,
			age: 15,
		})
	break
	}
}

按以上代码这样写,我们发现会特别冗余,假设这不是case,那我们需要执行多少次setState方法呢?所以我们可以更改成以下简便的写法:

changeOnTab(num){
	const state = {
		username: dd,
		age: 15,
	}
	switch(num){
		case 1:
			state.username = mm,
			state.age = 14
		break
		case 2:
			state.username = mm,
		break
	}
	this.setState(state);
}

参考文档:
https://juejin.im/post/5ad458c7f265da239c7bd37c
http://www.runoob.com/react/react-state.html

猜你喜欢

转载自blog.csdn.net/sinat_32206135/article/details/85119498