生命周期,鈎子函數:
掛載階段:
一、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判斷、實例化,這樣就可以解決這個問題。