天天看點

React之ReactHook與生命周期

useEffect

useEffect第一個參數為callback,傳回destory,destory作為下一次callback執行前調用,用于清除上一次callback産生的副作用。

第二個參數為依賴項,是一個數組,可以有多個依賴性,依賴項改變,執行上一次callback傳回的destory,和執行新的effect第一個參數callback。

對于 useEffect 執行, React 處理邏輯是采用異步調用 ,對于每一個 effect 的 callback, React 會向 ​

​setTimeout​

​回調函數一樣,放入任務隊列,等到主線程任務完成,DOM 更新,js 執行完成,視圖繪制完畢,才執行。是以 effect 回調函數不會阻塞浏覽器繪制視圖。

useLayoutEffect

useLayoutEffect 與useEffect 不同的是,它采用的是同步執行。
  1. useLayoutEffect是在DOM更新之後,遊覽器繪制之前,(也就是說,它執行的時候,DOM是已經更新了的,隻不過遊覽器還沒有繪制)這樣可以友善修改DOM,擷取DOM資訊,但是這樣遊覽器隻會繪制一次,如果修改DOM布局放在useEffect,那麼useEffect執行是在遊覽器繪制試圖之後,接下來又改DOM,就可能會導緻遊覽器再次回流跟重繪。
  2. uselayoutEffect 的 callback中代碼執行會阻塞遊覽器繪制

總結

  • useEffect 和 useLayoutEffect的差別: 修改DOM,改變布局就用useLayoutEffect,其它全用useEffect。

問: useEffect 與 componentDIdMout 以及 componentDidUpdate執行時機有什麼樣的差別?

答:useEffect對react是異步執行,而componentDIdMount 以及 componentDidUpdate是同步執行。useEffect不會阻塞遊覽器繪制。

useInsertionEffect - react 18 新hook

useInsertionEffect的出現,本質上是為了解決css-in-js 在渲染中注入樣式的性能問題。

它的執行是高于useLayoutEffect的。它執行的時候,DOM還沒有更新。

它的産生是基于如下條件:

  1. useLayoutEffect執行的時候DOM已經更新完成了,布局也是已經确定了,剩下的就是交給遊覽器繪制。
  2. 如果在useLayoutEffect動态生成style标簽,那麼會再次影響布局,導緻遊覽器再次重回和重排。
這時候useInsertionEffect 就出現了,它的執行是在DOM更新之前,是以此時使用css-in-js避免了遊覽器再次出現重回重排的可能。

模拟:

React之ReactHook與生命周期
頁面初始化執行-useEffect

useEffect(() => {
    // 請求資料,事件監聽,操縱dom
},[])
頁面解除安裝執行 - use Effect+ componentWillUnmount

useEffect(() => {
    return function componentWillUnmount(){
        // 解除事件監聽,清除計時器,延時器。
    }
},[])
元件更新完成

useEffect(() => {
    console.log("元件更新完成")
})      
import React,{useState} from "react"

function FunctionLifecycle(props){
    const [ num , setNum ] = useState(0)
    React.useEffect(()=>{
        /* 請求資料 , 事件監聽 , 操縱dom  , 增加定時器 , 延時器 */
        console.log('元件挂載完成:componentDidMount')
        return function componentWillUnmount(){
            /* 解除事件監聽器 ,清除 */
            console.log('元件銷毀:componentWillUnmount')
        }
    },[])/* 切記 dep = [] */

    React.useEffect(()=>{
        console.log('props變化:componentWillReceiveProps')
    },[ props ])
    
    React.useEffect(()=>{ /*  */
        console.log(' 元件更新完成:componentDidUpdate ')
    })
    return <div>
        <div> props : { props.number } </div>
        <div> states : { num } </div>
        <button onClick={ ()=> setNum(state=>state + 1) }   >改變state</button>
    </div>
}

// eslint-disable-next-line import/no-anonymous-default-export
export default ()=>{
    const [ number , setNumber ] = React.useState(0)
    const [ isRender , setRender ] = React.useState(true)
    return <div>
        { isRender &&  <FunctionLifecycle number={number}  /> }
        <button onClick={ ()=> setNumber(state => state + 1 ) } > 改變props  </button> <br/>
        <button onClick={()=> setRender(false) } >解除安裝元件</button>
    </div>
}      

繼續閱讀