React(四)
-
- 一、事件總線
- 二、關于setState的原理
-
- 1. setState的三種使用方式
-
- (1)基本使用
- (2)傳入一個回調
- (3)第一個參數是對象,第二個參數是回調
- 2. 為什么setState要設置成異步
-
- (1)提升性能,減少render次數
- (2)避免state和props數據不同步
- 3. 獲取異步修改完數據的結果
- 三、PureComponent監測數據的原理
-
- 1. 先來看一個問題
- 2. sholdComponentUpdate()
- 3. 引出PureComponent
-
- (1)類組件
- (2)函數組件
- 4. PureComponent只監測第一層
- 5. PureComponent如何監測深層數據的改變
- 四、ref獲取元素或組件實例
-
- 1. ref的三種用法
- 2. ref獲取類組件實例
- 3. ref獲取函數組件內的某個元素
一、事件總線
這里的事件總線和vue中基本一個思路。
在React中可以通過第三方庫來進行任意組件通信,安裝:
npm install hy-event-store
使用:
1、在某個地方新建jsx文件對外暴露事件總線
// 創建事件總線
import { HYEventBus } from 'hy-event-store';
const eventBus = new HYEventBus();export default eventBus;
2、在需要接收值的組件中,在掛在完畢的生命周期函數中綁定事件和被觸發時的回調,最好寫上銷毀的代碼:
//事件的回調getData(name,age) {console.log(name,age,this);this.setState({name: name, age: age})}//1.掛載完畢后綁定事件接收別的地方傳過來的值componentDidMount() {eventBus.on('getData', this.getData.bind(this))}//3.銷毀的時候解綁componentWillUnmount() {eventBus.off('getData', this.getData)}
3、另一個組件觸發,并傳值
sendData() {//2.某個組件中觸發事件并傳值eventBus.emit('getData', 'zzy', 18)}render() {return (<div><h1>GrandSon組件</h1><button onClick={() => this.sendData()}>點擊傳值給App</button></div>)}
二、關于setState的原理
開發中我們并不能直接通過修改state的值來讓界面發生更新:
因為我們修改了state之后,希望React根據最新的State來重新渲染界面,但是這種方式的修改React并不知道數據發生了變化;
React并沒有實現類似于Vue2中的Object.defineProperty
或者Vue3中的Proxy
的方式來通過數據劫持
監聽數據的變化;
我們必須通過setState
來告知React數據已經發生了變化;
源碼先簡單lou一眼:
1. setState的三種使用方式
我們基于以下組件進行操作
export class Son extends React.Component {constructor() {super();this.state = {name: 'zzy',age: 18,}}changeName() {this.setState(...)}render() {return (<div><h1>{this.state.name}</h1><button onClick={() => this.changeName()}>點擊修改名字</button></div>)}
}
(1)基本使用
我們之前用的最多的就是直接傳入一個配置對象,然后給state中數據重新賦值。這里的原理是借助了Object.assign(state, newState)
對state
和傳入的對象進行合并,如果key
重復那么就進行值的覆蓋,沒改的繼續保留
//1.基本使用,傳入配置對象,不是覆蓋原來的state,而是進行對象的合并
this.setState({name: 'ht' //原理:對象的合并Object.assign(state, newState)
})
(2)傳入一個回調
setState
的參數除了可以傳配置對象外,還可以傳入一個回調函數,通過return
一個對象,對象中包含我們要修改的值,也可以實現數據的更新和頁面的重新渲染。
這個回調可以接收兩個參數:state和props
,分別對應的是上一個修改狀態
的state
和props
的值們。
注意是上一個修改狀態!如果在一個回調中多次執行setState
更改數據,那么參數state保存的是上一個修改狀態的值!如果不明白請看本節2.1.1部分
//2.傳入一個回調,可以接收修改之前的state和props
this.setState((state,props) => {console.log(state,props);return {name: 'ht' //這里也可以進行更改}
})
(3)第一個參數是對象,第二個參數是回調
setState
是一個異步調用。
如果在setState
下面使用name
,我們會發現拿到的是原來的name
,這就證明了setState
是一個異步調用,那么如果我們想在數據變化后再基于數據進行一些操作怎么辦?這時候可以傳入第二個參數:一個回調函數,該回調函數執行的時機就是數據更新完且render調用完畢后
。
//3.setState是一個異步調用
//如果想等數據更新后做一些操作,可以傳入第二個參數:回調
//第二個參數執行的時機就是數據更新完之后
this.setState({ name