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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章