react生命周期的鈎子函數


生命周期,鈎子函數:

掛載階段:

一、constructor (第一個執行)

​ 1.可以初始化組件狀態

​ 2.可以給一些事件函數綁定this

注意:不能再內部調用setState()

constructor(){
  super()
  this.state={
    n:1
  }
  //不能在內部調用setState()
  //this.setState({n:2})
  this.handleClick = this.handleClick.bind(this)   //2.用來綁定this
}
 handleClick(){   //不是用的箭頭函數的話,就需要用到constructor這個函數。
   console.log(this)
 }
render(){
    return (
      <div>
        app
       {<button onClick = {this.handleClick}>點我哦</button>}
        <button>點我哦</button>
      </div>
    )
  }

二、static getDerivedStateFromProps(){} 類的函數 (真實屬於第二次執行的)

執行時機:

  • ​ 初始化執行
  • ​ props | setState | forceUpdate 都會執行

一旦組件里面的狀態依靠屬性的變化而變化,那么你就用到此鈎子函數

​ 這個鈎子函數屬於類,前面需要加static修飾

​ 子組件在constructor直接拿傳過來的屬性是拿不到的,除非在constructor傳入屬性props

​ 讓組件內部的派生狀態始終區別於外部傳入的屬性的值,只有外部傳入的屬性改變了,自身的狀態才會發生變化

​ 必須要有返回值,返回什么state里面就變成什么?

​ 在這個鈎子函數里面,所以內部是不能訪問this的

在父組件定義一個狀態。

constructor(){
  super()
  this.state={
    n:1  //定義了一個狀態
  }
}
 render(){
    return (
      <div>
        <button onClick={()=>{this.setState({n:this.state.n+1})}}>點我哦</button>
        <One n={this.state.n}/>
      </div>
    )
  }

在子組件接收,使用的時候,如果僅想外部控制外部傳遞過來的屬性,就需要加上該鈎子函數即:

如果你的組件的某個狀態就想由外部傳入的屬性進行關聯控制,希望屬性改變了,組件內部的狀態也發生變化,那么 就把這個狀態變成派生狀態,使用此鈎子函數即可。一旦組件里面的狀態依靠屬性的變化而變化,那么你就用到此鈎子函數

接收子組件狀態:
constructor(props){
        super(props)
        console.log("one-construcotr1",props.n)
        this.state={
            oneN:props.n
        }
    }
    
    static getDerivedStateFromProps(props){//外面可以傳入數據,
       console.log("getDerivedStateFromProps") //內部是不能訪問this的
       return{   //必須要返回一個東西,null都是可以的
         oneN:props.n//返回什么,就把定義的狀態變成什么
       }
   } 
   render() {
        return (
            <div>
                <button onClick={()=>{this.setState({oneN:1000})}}>更改自身狀態</button>   //加上上面的函數,該按鈕就沒有作用了,不能內部執行。
                one --- {this.state.oneN}
            </div>
        )
    }

三、render 可執行多次 (第三個執行)

​ 1.初始化立即執行(constructor)

​ 2.render鈎子函數什么時候執行?

​ (1)初始化的時候執行一次

​ (2)組件內部調用setState | 外部傳入Props改變(New props) | forceUpdate(強制更新)

四、componentDIdMount 只執行一次, (第四個執行)

組件掛載完以后,只執行一次,

即將過期的函數。

17.x版本中不推薦使用的鈎子函數
UNSAFE_componentWillMount 不建議用,可以會出現bug,不能初始化因為會受到React16.xFiber的協調算法,函數會執行多次,如果把異步請求放到該鈎子函數中,異步請求可能也會執行多次。

UNSAFE_componentWillReceiveProps
UNSAFE_componentWillUpdate
componentWillMount vs componentDidMount (在哪個鈎子函數里面進行異步請求?)

子父組件的時候,會按照上面的順序,執行順序為

父組件constructor ->父組件render->子組件constructor ->子組件render->子組件componentDIdMount->父組件componentDIdMount

父組件:

constructor(){
    super()
    console.log("App-constructor")
    this.state = {
      n:1
    }
  }

  componentDidMount(){
  	 console.log("App-componentDidMount")
  }

  render(){
  	console.log("App-render")
    return (
      <div>
        <button onClick={()=>{this.setState({n:this.state.n+1})}}>點我哦</button>
        <One n={this.state.n}/>
      </div>
    )
  }

子組件:

constructor(){
    super()
    console.log("one-constructor")
  }

  componentDidMount(){
  	 console.log("one-componentDidMount")
  }

  render(){
  	console.log("one-render")
    return (
      <div>
        one
      </div>
    )
  }
卸載時

componentWillUnmount

消除定時器相關的操作。

//卸載時
componentWillUnmount(){
    console.log("組件被卸載了....")
    clearInterval(this.timer)
  }
//設置定時器
componentDidMount(){
    this.timer = setInterval(() => {
      console.log("timer....")
      this.setState({
        a:this.state.a+1
      })
    }, 2000);
  }
  //
render(){
    return (
      <div>
        <button onClick={()=>{ReactDOM.unmountComponentAtNode(document.getElementById("root"))}}>卸載組件</button>
        app --- {this.state.a}
      </div>
    )
  }
更新時的鈎子函數

​ getDerivedStateFromProps 在掛載階段已經講過。
​ shouldComponentUpdate
​ render 在掛載階段已經講過。
​ getSnapshotBeforeUpdate
​ componentDidUpdate

shouldComponentUpdate鈎子函數

注意:
shouldComponentUpdate 是可以用來提升react性能的鈎子函數! 可以減少一些render的執行次數
PureComponent 純組件,內部幫助實現了shouldComponentUpdate,相當於 Component+shouldComponentUpdate
內部采用了淺層比較:
如果基本類型,值不一樣,才會執行render渲染。
如果引用類型,地址不一樣,才會執行render渲染。

/*

​ 詢問組件是否進行更新操作,默認true,就會執行組件的更新操作。

​ 可以用來提升react的性能

注:內部通過this.props.flag獲取的是之前的flag值,

​ 如果想要獲取最新的,從參數里面獲取props.flag

​ 這個鈎子函數可以根據返回true或者返回false來去提升react性能

​ 根據外部傳入的屬性或者內部的狀態進行判斷,滿足某個條件下才去執行render渲染。

*/

shouldComponentUpdate(props,state){
        // console.log("shouldComponentUpdate",props.flag,this.props.flag)
        if(props.flag !== this.props.flag){
            return true
        }else{
            return false
        }  
    }

PureComponent 純組件

/**

* PureComponent 純組件 內部不能再去寫shouldComponentUpdate !!! (Component+shouldComponentUpdate)

* 純組件內部進行了淺層比較?

* 基本類型: 根據外部傳入的數據,新的數據與舊的數據是否一致,如果一致的話,render就不會執行。

* 引用類型: 根據外部傳入的數據,新的數據與舊的數據地址是否一致,如果一致的話,render也不會執行。

*/

export default class One extends PureComponent {

}

PureComponent 要依靠class才能使用。而React.memo()可以和functional component一起使用。

用法就是,直接把函數直接放到React.memo()里面就行了

getSnapshotBeforeUpdate --->目的是:返回快照作為componentDidUpdate第三個參數

在更新之前拿到之前的某些值,然后傳到 componentDidUpdate

可以返回一個快照作為componentDidUpdate的第三個參數使用即可。

使用方式:

getSnapshotBeforeUpdate(prevProps, prevState){

  console.log("getSnapshotBeforeUpdate...")

  return this.container.scrollHeight  //返回的數據被下面的snapshot接收(這是傳的是滾動高度。)

 }



 componentDidUpdate(prevProps, prevState, snapshot){

  console.log("componentDidUpdate...",snapshot)

  let dis = this.container.scrollHeight - snapshot; //生成新的數據 差值=新的高度-舊的高度

  this.container.scrollTop = this.container.scrollTop + dis;

 }

componentDidUpdate

可以結合swiper學習:查看版本:npm view swiper versions (6版本的有bug)

​ 下載合適的版本:yarn add swiper@5.2.0

正常情況下在componentDidMount里面實例化的話會出現無法滑動輪播圖的情況,所以可以在componentDidUpdate判斷、實例化,這樣就可以解決這個問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM