React 源碼探源 5 useEffect, useLayoutEffect

背景

接上一章 React 源碼探源 4 useState莫瞬,來研究一下 useEffect 與 useLayoutEffect 相關(guān)的實(shí)現(xiàn)細(xì)節(jié)咕缎。

相關(guān)定義

先來看一下 React 相關(guān)的官方文檔

  1. useEffect
    1. 作用:此 hook 主要是用來在組件渲染完成以后執(zhí)行一些稱為 effect 的操作冕象,例如發(fā)送 ajax 請(qǐng)求,打點(diǎn)汁蝶,當(dāng)一些 state 發(fā)生變化以后渐扮,再更新其它的 state 等。
    2. 執(zhí)行時(shí)機(jī):useEffect 實(shí)在下次渲染之前執(zhí)行掖棉,執(zhí)行時(shí)瀏覽器已經(jīng)對(duì)上次狀態(tài)更新渲染完成墓律。
    3. 返回值:useEffect可以返回一個(gè)回調(diào)函數(shù),當(dāng)組件 unMount 時(shí)幔亥,會(huì)被調(diào)用耻讽。
  2. useLayoutEffect
    1. 作用:如文檔所示,絕大部分情況下都推薦使用 useEffect帕棉,只有使用 useEffect 的結(jié)果有些怪異時(shí)才會(huì)使用這個(gè) hook针肥。 筆者根據(jù)實(shí)驗(yàn)發(fā)現(xiàn),只有更改 DOM 時(shí)導(dǎo)致了一些抖動(dòng)的行為時(shí)使用 useLayoutEffect 時(shí)才會(huì)派上用場(chǎng)香伴。
    2. 執(zhí)行時(shí)機(jī):useLayoutEffect 執(zhí)行時(shí)慰枕,瀏覽器還未對(duì) DOM 進(jìn)行渲染〖锤伲可以獲取新的 DOM 進(jìn)行操作具帮。執(zhí)行的時(shí)機(jī)較 useEffect 更早。
    3. 返回值:useLayoutEffect 也可以返回一個(gè)回調(diào)函數(shù),也會(huì)在 unMount 時(shí)被調(diào)用蜂厅。調(diào)用的時(shí)機(jī)也會(huì)較 useEffect 的回調(diào)更早匪凡。

示例代碼

本次實(shí)例使用的詳細(xì)代碼如下

function Dev() {
  const [count, setCount] = React.useState(0);
  React.useEffect(function effectCb() {
    console.log('in effect');
    if (count === 1) {
      setCount(10);
    }
    return function effectUnMount() {
      console.log('effect unmount');
    };
  }, [count]);
  React.useLayoutEffect(function layoutEffectCb() {
    console.log('in layout effect', count);
    return function layoutEffectUnMount() {
      console.log('layout effect unmount');
    };
  }, [count]);
  return (<div id="div">
    <button id="btn" onClick={() => {
      setCount(function add(c) {return c + 1;});
    }}>click me</button>
    <div>the new text is <span>{count}</span></div>
  </div>);
}

詳細(xì)流程

useEffect 和 useLayoutEffect 的詳細(xì)流程

render

  • 在執(zhí)行 useEffect, useLayoutEffect 時(shí)會(huì)將對(duì)應(yīng)的回調(diào)存儲(chǔ)起來,詳細(xì)結(jié)構(gòu)參加下部分
  • 更新時(shí)葛峻,會(huì)檢查對(duì)應(yīng)的 dependency 是不是有變化再?zèng)Q定是否將 effect 加進(jìn)來锹雏。

commit

  • useEffect 的列表會(huì)先被檢查,如果有更新术奖,會(huì)使用MessageChannel.postMessage 計(jì)劃在下次 eventLoop 執(zhí)行礁遵。從代碼注釋中看到,這樣的執(zhí)行方式比 setTimeout 要好采记,因?yàn)?setTimeout 至少有 4ms 的延遲佣耐。
  • useLayoutEffect 會(huì)在commitMutationEffects,也就是內(nèi)存中的 DOM 更新以后馬上執(zhí)行唧龄,執(zhí)行的時(shí)機(jī)比 useEffect 更早兼砖。
  • effect 執(zhí)行時(shí),會(huì)檢查 fiber 的 updateQueue 中是否含有對(duì)應(yīng)類型的 effect既棺,并將它順序執(zhí)行讽挟。
  • 執(zhí)行過程類似與 useState 的調(diào)用類似。
    • 通過 subtreeFlags 來檢查子節(jié)點(diǎn)是否有 effect 需要執(zhí)行丸冕。
    • 通過 flags 檢查當(dāng)前節(jié)點(diǎn)有 effect 需要執(zhí)行耽梅。

effect 數(shù)據(jù)結(jié)構(gòu)

可以看到以下的信息:

  1. useLayoutEffectuseEffect 生成的 hook 會(huì)跟useState生成的 hook 一起存儲(chǔ)在 fiber 的 memorizedState 下面的鏈表里面胖烛。
  2. fiber 的 updateQueue 使用 lastEffect 存儲(chǔ)著所有的 effect 生成的循環(huán)鏈表眼姐。
  3. hook 中的 memorizedStatelastEffect指向相同的地方,存儲(chǔ)著 effect 的相關(guān)信息
    • create: effect 的回調(diào)函數(shù)
    • tag: 存儲(chǔ)著 effect 的類型 Passive = 4標(biāo)記著 useEffect LayoutStatic = 2 標(biāo)記著 useLayoutEffect
    • destroy: effect 返回的回調(diào)函數(shù)
    • next: 下一個(gè)可能的 effect

unMount 過程

在組件卸載時(shí)佩番,執(zhí)行的順序和機(jī)制與加載和更新時(shí)一致众旗,只是在檢查到 fiber 被刪除時(shí)進(jìn)行操作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末趟畏,一起剝皮案震驚了整個(gè)濱河市贡歧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赋秀,老刑警劉巖利朵,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異沃琅,居然都是意外死亡哗咆,警方通過查閱死者的電腦和手機(jī)蜘欲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門益眉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事郭脂∧甑猓” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵展鸡,是天一觀的道長(zhǎng)屿衅。 經(jīng)常有香客問我,道長(zhǎng)莹弊,這世上最難降的妖魔是什么涤久? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮忍弛,結(jié)果婚禮上响迂,老公的妹妹穿的比我還像新娘。我一直安慰自己细疚,他們只是感情好蔗彤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疯兼,像睡著了一般然遏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吧彪,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天待侵,我揣著相機(jī)與錄音,去河邊找鬼来氧。 笑死诫给,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的啦扬。 我是一名探鬼主播中狂,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼扑毡!你這毒婦竟也來了胃榕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤瞄摊,失蹤者是張志新(化名)和其女友劉穎勋又,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體换帜,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楔壤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惯驼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹲嚣。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡递瑰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隙畜,到底是詐尸還是另有隱情抖部,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布议惰,位于F島的核電站慎颗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏言询。R本人自食惡果不足惜俯萎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望运杭。 院中可真熱鬧讯屈,春花似錦、人聲如沸县习。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躁愿。三九已至叛本,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間彤钟,已是汗流浹背来候。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逸雹,地道東北人营搅。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像梆砸,于是被迫代替她去往敵國和親转质。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • React Hook:使用 useEffect 一帖世、描述 Effect Hook 可以讓你能夠在 Function...
    Leson17閱讀 2,964評(píng)論 0 0
  • 1 關(guān)于hook 1.1 為什么使用hook 在react類組件(class)寫法中休蟹,有setState和生命周期...
    江湖yi山人閱讀 1,851評(píng)論 0 3
  • 如果你之前對(duì)于Hooks沒有了解,那么你可能需要看下概述部分日矫。你或許也可以在一些常見的問題中找到有用的信息赂弓。 基本...
    xiaohesong閱讀 21,081評(píng)論 4 11
  • react源碼解析10.commit階段 視頻課程(高效學(xué)習(xí)):進(jìn)入課程[https://xiaochen1024...
    全棧瀟晨閱讀 329評(píng)論 0 0
  • 在React v16.8新增了Hook,它提供了在函數(shù)組件中訪問狀態(tài)和React生命周期等能力哪轿,這些函數(shù)可以在程序...
    小小小小小粽子閱讀 493評(píng)論 0 0