欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React源碼state計算流程和優(yōu)先級實例解析

 更新時間:2022年11月08日 11:48:51   作者:goClient1992  
這篇文章主要為大家介紹了React源碼state計算流程和優(yōu)先級實例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

setState執(zhí)行之后會發(fā)生什么

setState 執(zhí)行之后,會執(zhí)行一個叫 enqueueSetState 的方法,這個主要作用是創(chuàng)建 Update 對象和發(fā)起調(diào)度,可以看下這個函數(shù)的邏輯,

enqueueSetState: function (inst, payload, callback) {
    // 1. inst是組件實例,從組件實例中拿到當前組件的Fiber節(jié)點
    var fiber = get(inst);
    var eventTime = requestEventTime();
    var lane = requestUpdateLane(fiber);
    // 2.1 根據(jù)更新發(fā)起時間、優(yōu)先級、更新的payload創(chuàng)建一個update對象
    var update = createUpdate(eventTime, lane);
    update.payload = payload;
    // 2.2 如果 setState 有回調(diào),順便把回調(diào)賦值給 update 對象的 callback 屬性
    if (callback !== undefined && callback !== null) {
      update.callback = callback;
    }
    // 3. 將 update 對象關聯(lián)到 Fiber 節(jié)點的 updateQueue 屬性中
    enqueueUpdate(fiber, update);
    // 4. 發(fā)起調(diào)度
    var root = scheduleUpdateOnFiber(fiber, lane, eventTime);
}

從上面源碼可以清晰知道,setState 調(diào)用之后做的4件事情

  • 根據(jù)組件實例獲取其 Fiber 節(jié)點
  • 創(chuàng)建 Update 對象
  • Update 對象關聯(lián)到 Fiber 節(jié)點的 updateQueue 屬性中
  • 發(fā)起調(diào)度

根據(jù)組件實例獲取其 Fiber 節(jié)點

其實就是拿組件實例中的 _reactInternals 屬性,這個就是當前組件所對應的 Fiber 節(jié)點

function get(key) {
  return key._reactInternals;
}

題外話:react利用雙緩存機制來完成 Fiber 樹的構(gòu)建和替換,也就是 currentworkInProgress 兩棵樹,那 enqueueSetState 里面拿的是那棵樹下的 Fiber 節(jié)點呢?

答案是:current樹下的Fiber節(jié)點。具體的原理在下面update對象丟失問題再說明

創(chuàng)建update對象

function createUpdate(eventTime, lane) {
  var update = {
    eventTime: eventTime,
    lane: lane,
    tag: UpdateState,
    payload: null,
    callback: null,
    next: null
  };
  return update;
}

屬性的含義如下:

  • eventTime:update對象創(chuàng)建的時間,用于ensureRootIsScheduled計算過期時間用
  • lane:此次更新的優(yōu)先級
  • payload:setState的第一個參數(shù)
  • callback:setState的第二個參數(shù)
  • next:連接的下一個 update 對象

將Update對象關聯(lián)到Fiber節(jié)點的updateQueue屬性

這里執(zhí)行的是 enqueueUpdate 函數(shù),下面是我簡化過后的邏輯

function enqueueUpdate(fiber, update) {
    var updateQueue = fiber.updateQueue;
    var sharedQueue = updateQueue.shared;
    var pending = sharedQueue.pending;
    if (pending === null) {
      update.next = update;
    } else {
      update.next = pending.next;
      pending.next = update;
    }
    sharedQueue.pending = update;
}

可以看到這里的邏輯主要是將 update 對象放到 fiber 對象的 updateQueue.shared.pending 屬性中, updateQueue.shared.pending 是一個環(huán)狀鏈表。

那為什么需要把它設計為一個環(huán)狀鏈表?我是這樣理解的

  • shared.pending 存放的是鏈表的最后一個節(jié)點,那么在環(huán)狀鏈表中,鏈表的最后一個節(jié)點的next指針,是指向環(huán)狀鏈表的頭部節(jié)點,這樣我們就能快速知道鏈表的首尾節(jié)點
  • 當知道首尾節(jié)點后,就能很輕松的合并兩個鏈表。比如有兩條鏈表a、b,我們想要把 b append到 a 的后面,可以這樣做
const lastBPoint = bTail
const firstBPoint = bTail.next
lastBPoint.next = null
aTail.next = firstBPoint
aTail = lastBPoint

后面即使有c、d鏈表,同樣也可以用相同的辦法合并到a。react 在構(gòu)建 updateQueue 鏈表上也用了類似的手法,新產(chǎn)生的 update 對象通過類似上面的操作合并到 updateQueue 鏈表,

發(fā)起調(diào)度

enqueueUpdate 末尾,執(zhí)行了 scheduleUpdateOnFiber 函數(shù),該方法最終會調(diào)用 ensureRootIsScheduled 函數(shù)來調(diào)度react的應用根節(jié)點。

當進入 performConcurrentWorkOnRoot 函數(shù)時,就代表進入了 reconcile 階段,也就是我們說的 render 階段。render 階段是一個自頂向下再自底向上的過程,從react的應用根節(jié)點開始一直向下遍歷,再從底部節(jié)點往上回歸,這就是render階段的節(jié)點遍歷過程。

這里我們需要知道的是,在render階段自頂向下遍歷的過程中,如果遇到組件類型的Fiber節(jié)點,我們會執(zhí)行 processUpdateQueue 函數(shù),這個函數(shù)主要負責的是組件更新時 state 的計算

processUpdateQueue做了什么

processUpdateQueue函數(shù)主要做了三件事情

  • 構(gòu)造本輪更新的 updateQueue,并緩存到 currentFiber 節(jié)點中
  • 循環(huán)遍歷 updateQueue,計算得到 newState,構(gòu)造下輪更新的 updateQueue
  • 更新 workInProgress 節(jié)點中的 updateQueue、memoizedState 屬性

這里的 updateQueue 并不指代源碼中 Fiber 節(jié)點的 updateQueue,可以理解為從 firstBaseUpdatelastBaseUpdate 的整條更新隊列。這里為了方便描述和理解,直接用 updateQueue 替代說明。

變量解釋

因為涉及的變量比較多,processUpdateQueue 函數(shù)的邏輯看起來并不怎么清晰,所以我先列出一些變量的解釋方便理解

  • shared.pending:

enqueueSetState 產(chǎn)生的 update對象 環(huán)形鏈表

  • first/lastBaseUpdate:-- 下面我會用 baseUpdate 代替

當前 Fiber 節(jié)點中 updateQueue 對象中的屬性,代表當前組件整個更新隊列鏈表的首尾節(jié)點

  • first/lastPendingUpdate:下面我會用 pendingUpdate 代替

shared.pending 剪開后的產(chǎn)物,分別代表新產(chǎn)生的 update對象 鏈表的首尾節(jié)點,最終會合并到 currentFiber 和 workInProgress 兩棵樹的更新隊列尾部

  • newFirst/LastBaseUpdate:下面我會用 newBaseUpdate 代替

newState計算過程會得到,只要存在低優(yōu)先級的 update 對象,這兩個變量就會有值。這兩個變量會賦值給 workInProgress 的 baseUpdate,作為下一輪更新 update對象 鏈表的首尾節(jié)點

  • baseState:newState 計算過程依賴的初始 state
  • memoizedState:當前組件實例的 state,processUpdateQueue 末尾會將 newState 賦值給這個變量,

構(gòu)造本輪更新的 updateQueue

上面我們說到 shared.pendingenqueueSetState 產(chǎn)生的 update對象 環(huán)形鏈表,在這里我們需要剪斷這個環(huán)形列表取得其中的首尾節(jié)點,去組建我們的更新隊列。那如何剪斷呢?

shared.pending 是環(huán)形鏈表的尾部節(jié)點,它的下一個節(jié)點就是環(huán)形鏈表的頭部節(jié)點,參考上一小節(jié)我們提到的鏈表合并操作。

var lastPendingUpdate = shared.pending;
var firstPendingUpdate = lastPendingUpdate.next;
lastPendingUpdate.next = null;

這樣就能剪斷環(huán)形鏈表,拿到我們想要的新的 update 對象 —— pendingUpdate。接著我們要拿著這個 pendingUpdate 做兩件事情:

  • pendingUpdate 合并到當前Fiber節(jié)點的更新隊列
  • pendingUpdate 合并到 currentFiber樹 中對應 Fiber節(jié)點 的更新隊列

為什么要做這兩件事情?

  • 第一個是解決狀態(tài)連續(xù)性問題,當出現(xiàn)多個 setState 更新時,我們要確保當前 update對象 的更新是以前一個 update對象 計算出來的 state 為前提。所以我們需要構(gòu)造一個更新隊列,新的 update對象 要合并到更新隊列的尾部,從而維護state計算的連續(xù)性
  • 第二個是解決 update 對象丟失問題。在 shared.pending 被剪開之后,shared.pending會被賦值為null,當有高優(yōu)先級任務進來時,低優(yōu)先級任務就會被打斷,也就意味著 workInProgress 樹會被還原,shared.pending 剪開之后得到的 pendingUpdate 就會丟失。這時就需要將 pendingUpdate 合并到 currentFiber樹 的更新隊列中

接下來可以大致看一下這一部分的源碼

  var queue = workInProgress.updateQueue;
  var firstBaseUpdate = queue.firstBaseUpdate;
  var lastBaseUpdate = queue.lastBaseUpdate;
  // 1. 先拿到本次更新的 update對象 環(huán)形鏈表
  var pendingQueue = queue.shared.pending;
  if (pendingQueue !== null) {
    // 2. 清空pending
    queue.shared.pending = null;
    var lastPendingUpdate = pendingQueue;
    var firstPendingUpdate = lastPendingUpdate.next;
    // 3. 剪開環(huán)形鏈表
    lastPendingUpdate.next = null;
    // 4. 將 pendingupdate 合并到 baseUpdate
    if (lastBaseUpdate === null) {
      firstBaseUpdate = firstPendingUpdate;
    } else {
      lastBaseUpdate.next = firstPendingUpdate;
    }
    lastBaseUpdate = lastPendingUpdate;
    // 5. 將 pendingupdate 合并到 currentFiber樹的 baseUpdate
    var current = workInProgress.alternate;
    if (current !== null) {
      var currentQueue = current.updateQueue;
      var currentLastBaseUpdate = currentQueue.lastBaseUpdate;
      if (currentLastBaseUpdate !== lastBaseUpdate) {
        if (currentLastBaseUpdate === null) {
          currentQueue.firstBaseUpdate = firstPendingUpdate;
        } else {
          currentLastBaseUpdate.next = firstPendingUpdate;
        }
        currentQueue.lastBaseUpdate = lastPendingUpdate;
      }
    }
  }

源碼看起來很多,但本質(zhì)上只做了一件事,從源碼中可以看出這部分主要就是把 shared.pending 剪開,拿到我們的 pendingUpdate,再把 pendingUpdate 合并到本輪更新和 currentFiber 節(jié)點的 baseUpdate 中。

計算 newState

在這部分的源碼中,除了計算 newState,還有另外一個重要工作是,構(gòu)造下一輪更新用的 updateQueue。

到這里可能會有疑問,為什么需要構(gòu)造下輪更新的 updateQueue,本輪更新我們把 shared.pending 里面的對象遍歷計算完,再把 state 更新,下輪更新進來再根據(jù)這個 state 計算不行好了嗎?

如果沒有高優(yōu)先級任務打斷機制,確實是不需要在這里構(gòu)造下輪更新的 updateQueue,因為每輪更新我們只會依賴當前的 state 和 shared.pending

打斷機制下,低優(yōu)先級任務重啟后的執(zhí)行,需要依賴完整的更新隊列才能保證 state 的連續(xù)性和正確性。下面我舉個例子

state = { count: 0 }
componentDidMount() {
    const button = this.buttonRef.current
    // 低優(yōu)先級任務
    setTimeout(() => this.setState({ count: 1 }), 1000)
    // 高優(yōu)先級任務
    setTimeout(() => button.click(), 1040)
}
handleButtonClick = () => {
    this.setState( prevState => {
      return { count: prevState.count + 2 }
    } )
}

我們期望能實現(xiàn)的效果是 0 -> 2 -> 3,需求如下:

  • 高優(yōu)先級任務打斷低優(yōu)先級任務之后,不以低優(yōu)先級任務計算得到的baseState做計算
  • 低優(yōu)先級任務重啟后,不能覆蓋高優(yōu)先級任務計算得到的值,且需要根據(jù)低優(yōu)先級任務計算得到的newState,作為高優(yōu)先級的baseState再去執(zhí)行一次高優(yōu)先級任務

知道了需求,我們可以大概列一下實現(xiàn)思路:

  • 低優(yōu)先級任務打斷后,高優(yōu)先級任務執(zhí)行之前,需要還原到低優(yōu)先級任務執(zhí)行之前的 workInPregress 節(jié)點,確保不受低優(yōu)先級任務計算得到的 baseState 影響
  • 需要維護一個更新對象隊列,按執(zhí)行順序存儲 update 對象,確保低優(yōu)先級重啟后,依然會執(zhí)行高優(yōu)先級任務

上面說的需求和實現(xiàn)思路在 react 的源碼中實現(xiàn)其實是非常簡單的,但要理解其中的含義可能需要費點功夫,下面可以看看我改動過后的源碼,可以直接從 do...while 開始看

  function cloneUpdate(update) {
      return {
          eventTime: update.eventTime,
          lane: update.lane,
          tag: update.tag,
          payload: update.payload,
          callback: update.callback,
          next: null
      };
  }
  if (firstBaseUpdate !== null) {
    var newState = queue.baseState;
    var newBaseState = null;
    var newFirstBaseUpdate = null;
    var newLastBaseUpdate = null;
    var update = firstBaseUpdate;
    // 遍歷 updateQueue
    do {
      var updateLane = update.lane;
      var updateEventTime = update.eventTime;
      // 校驗當前 update 對象夠不夠優(yōu)先級
      if (!isSubsetOfLanes(renderLanes, updateLane)) {
        // 優(yōu)先級不夠,我們需要從當前 update 對象開始重新構(gòu)造一個更新隊列
        var clone = cloneUpdate(update)
        if (newLastBaseUpdate === null) {
          newFirstBaseUpdate = newLastBaseUpdate = clone;
          // 當前的 newState 就作為下輪更新的 baseState 使用
          newBaseState = newState;
        } else {
          newLastBaseUpdate = newLastBaseUpdate.next = clone;
        }
      } else {
        // 優(yōu)先級夠
        if (newLastBaseUpdate !== null) {
          // newLastBaseUpdate 不為空,就代表存在優(yōu)先級不夠的 update 對象
          var _clone = cloneUpdate(update)
          // 為保證狀態(tài)連續(xù)性,即使當前 update 對象優(yōu)先級足夠,也要被放到 updateQueue 中
          newLastBaseUpdate = newLastBaseUpdate.next = _clone;
        }
        // 計算newState
        newState = getStateFromUpdate(workInProgress, queue, update, newState, props, instance);
      }
      update = update.next;
    } while (update);

邏輯如下:

優(yōu)先級不夠

  • 重新構(gòu)造更新隊列 newBaseUpdate,留到低優(yōu)先級任務重啟遍歷
  • 記錄當前 newState,留到低優(yōu)先級任務重啟作為 baseState 計算

優(yōu)先級足夠

  • 看看 newBaseUpdate 有沒有東西,有東西就把當前 update 對象也合并進去
  • 計算 newState

這里 newState 的計算邏輯很簡單

  • payload是值。用對象包裹合并到 prevState 即可
  • payload是函數(shù)。傳入 prevState 計算,將函數(shù)返回值也合并到 prevState 即可

更新 workInProgress 節(jié)點

更新 workInProgress 節(jié)點屬性的邏輯不多,主要就是把 newBaseState、newBaseUpate 賦值給 workInProgress 節(jié)點,作為下一輪更新的 baseState 和更新隊列使用

if (newLastBaseUpdate === null) {
  newBaseState = newState;
}
queue.baseState = newBaseState;
queue.firstBaseUpdate = newFirstBaseUpdate;
queue.lastBaseUpdate = newLastBaseUpdate;
workInProgress.memoizedState = newState;
  • 如果 newLastBaseUpdate 為空,代表所有 update 對象為空,本輪更新計算得到的 newState 可以完全作為下輪更新的 baseState 使用。否則只能用出現(xiàn)首個不夠優(yōu)先級的 update 對象時緩存下來的 newState 作為下輪更新的 baseState
  • 更新 baseUpdate,當所有 update 對象優(yōu)先級足夠,baseUpdate 的值一般為空。只有存在優(yōu)先級不夠的 update 對象時,才會有值
  • newState 賦值給 memoizedStatememoizedState 代表當前組件的所有 state

總結(jié)

看到上面的原理解析是不是很復雜,我們可以忽略所有的實現(xiàn)細節(jié),回歸現(xiàn)象本質(zhì),state計算就是遍歷 update對象 鏈表根據(jù) payload 得到新的state。在此前提下,因為優(yōu)先級機制,打斷之后會還原 workInProgress 節(jié)點,從而會引起 update對象 丟失問題 和 state計算連續(xù)性問題。解決這兩個問題才是我們上面說的復雜的實現(xiàn)細節(jié)

update對象丟失問題

為什么會丟失

我們知道高優(yōu)先級任務進來會打斷低優(yōu)先級任務的執(zhí)行,打斷之后會將當前的 workInProgress 節(jié)點還原為開始的狀態(tài),也就是可以理解為會將 workInProgress 樹還原為當前頁面所渲染的 currentFiber 節(jié)點。當 workInProgress 節(jié)點還原之后,我們本來存在 workInProgress 中的 updateQueue 屬性也會被重置,那就意味著低優(yōu)先級的 update 對象會丟失。

上面說到的,setState產(chǎn)生的新 update對象 是會放在 currentFiber 節(jié)點上也是這個原因,如果 setState 產(chǎn)生的新 update對象 放到 workInProgress 上,只要 workInProgress 被還原,這些 update對象 就會丟失

如何解決

我們在 processUpdateQueue 函數(shù)的開始階段,將新產(chǎn)生的 update 對象,也就是 shared.pending 中的值,合并到 currentFiber( workInProgress.alternate ) 節(jié)點的 firstBaseUpdatelastBaseUpdate。具體規(guī)則如下

  • currentFiber 節(jié)點不存在 lastBaseUpdate,將新的 update 對象賦值給 currentFiber 節(jié)點的 firstBaseUpdatelastBaseUpdate 屬性
  • currentFiber 節(jié)點存在 lastBaseUpdate,將新的 update 對象拼接到 currentFiber 節(jié)點的 lastBaseUpdate 節(jié)點后面,也就是說新的 update 對象會成為 currentFiber 節(jié)點新的 lastBaseUpdat 節(jié)點

還原 workInProgress 節(jié)點執(zhí)行的函數(shù)是 prepareFreshStack,里面會用 currentFiber 節(jié)點的屬性覆蓋 workInProgress 節(jié)點,從而實現(xiàn)還原功能。所以就算 workInProgress 節(jié)點被重置,我們只要把 update對象 合并到 currentFiber 節(jié)點上,還原的時候依然會存在于新的 workInProgress 節(jié)點

state計算的連續(xù)性

問題現(xiàn)象

我們上面說到,低優(yōu)先級任務重啟,不能覆蓋高優(yōu)先級任務計算得到的值,且需要根據(jù)低優(yōu)先級任務計算得到的newState,作為高優(yōu)先級的baseState再去執(zhí)行一次高優(yōu)先級任務。什么意思呢這是?

state = { count: 0 }
componentDidMount() {
    const button = this.buttonRef.current
    // 低優(yōu)先級任務 - AUpate
    setTimeout(() => this.setState({ count: 1 }), 1000)
    // 高優(yōu)先級任務 - BUpdate
    setTimeout(() => button.click(), 1040)
}
handleButtonClick = () => {
    this.setState( prevState => {
      return { count: prevState.count + 2 }
    } )
}

上面代碼所產(chǎn)生的update對象如下

AUpate = { lane: 低, payload: 1 }
BUpdate = { lane: 高, payload: state => ({ count: state.count + 2 }) }
  • 先執(zhí)行 AUpdate 任務
  • AUpdate 的優(yōu)先級比 BUpdate 的低,BUpdate 會打斷 AUpdate 的執(zhí)行。
  • 那么 BUpdate 執(zhí)行完,count的值為2 問題來了
  • BUpdate 是后進來的,AUpdate 不能覆蓋掉 BUpdate 的結(jié)果
  • AUpdate 執(zhí)行的結(jié)果 count 會變成 1,那么 BUpdate 的結(jié)果需要在此基礎上計算,也就是要得到3

這也就決定了我們要用隊列的形式去存儲所有 update對象。update對象的存儲順序決定了state計算的前后依賴性,從而保證狀態(tài)的連續(xù)性和準確性

明確很重要的一點,優(yōu)先級高低只會影響某個 update對象 是否會提前執(zhí)行,不會影響最終的 state 結(jié)果。最終的 state 結(jié)果還是由更新隊列中 update對象 的順序決定的

如何解決

我們看到 processUpdateQueue 中有兩部分都是在構(gòu)造更新隊列的

  • 一部分是位于函數(shù)開頭的,將 update對象 合并到 currentFiber 節(jié)點
  • 一部分是位于函數(shù)末尾的,將 newBaseUpdate 賦值給 workInProgress 節(jié)點 這兩部分雙劍合璧就完美解決我們的需求,currentFiber 是作用于本輪更新,workInProgress 則作用于下一輪更新,因為雙緩存機制的存在,在 commit階段 結(jié)尾,react 應用根節(jié)點的 current 指針就會指向 workInProgress 節(jié)點,workInProgress 節(jié)點在下一輪更新就會變成 currentFiber 節(jié)點。

這樣無論是什么優(yōu)先級,只要按順序構(gòu)造出更新隊列,我就能計算出正確的newState,同時利用隊列的性質(zhì),保證 update對象 間 state計算 的連續(xù)性

以上就是React源碼state計算流程和優(yōu)先級實例解析的詳細內(nèi)容,更多關于React state計算流程優(yōu)先級的資料請關注腳本之家其它相關文章!

相關文章

  • 代碼解析React中setState同步和異步問題

    代碼解析React中setState同步和異步問題

    前端框架從MVC過渡到MVVM。從DOM操作到數(shù)據(jù)驅(qū)動,一直在不斷的進步著,本文給大家介紹React中setState同步和異步問題,感興趣的朋友一起看看吧
    2021-06-06
  • 聊聊React onClick 傳遞參數(shù)的問題

    聊聊React onClick 傳遞參數(shù)的問題

    很多朋友向小編反映一個問題關于React onClick 傳遞參數(shù)的問題,當點擊刪除按鈕需要執(zhí)行刪除操作,針對這個問題該如何處理呢?下面小編給大家?guī)砹薘eact onClick 傳遞參數(shù)的問題,感興趣的朋友一起看看吧
    2021-10-10
  • React中異步數(shù)據(jù)更新不及時問題及解決

    React中異步數(shù)據(jù)更新不及時問題及解決

    這篇文章主要介紹了React中異步數(shù)據(jù)更新不及時問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 如何用webpack4.0擼單頁/多頁腳手架 (jquery, react, vue, typescript)

    如何用webpack4.0擼單頁/多頁腳手架 (jquery, react, vue, typescript)

    這篇文章主要介紹了如何用webpack4.0擼單頁/多頁腳手架 (jquery, react, vue, typescript),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-06-06
  • react實現(xiàn)動態(tài)表單

    react實現(xiàn)動態(tài)表單

    這篇文章主要為大家詳細介紹了react實現(xiàn)動態(tài)表單,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • React性能debug場景解決記錄

    React性能debug場景解決記錄

    這篇文章主要為大家介紹了React性能debug場景解決記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • React實現(xiàn)二級聯(lián)動的方法

    React實現(xiàn)二級聯(lián)動的方法

    這篇文章主要為大家詳細介紹了React實現(xiàn)二級聯(lián)動的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 探究react-native 源碼的圖片緩存問題

    探究react-native 源碼的圖片緩存問題

    本篇文章主要介紹了探究react-native 源碼的圖片緩存問題,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • react render props模式實現(xiàn)組件復用示例

    react render props模式實現(xiàn)組件復用示例

    本文主要介紹了react render props模式實現(xiàn)組件復用示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • React實現(xiàn)圖片懶加載的常見方式

    React實現(xiàn)圖片懶加載的常見方式

    圖片懶加載是一種優(yōu)化網(wǎng)頁性能的技術,它允許在用戶滾動到圖片位置之前延遲加載圖片,通過懶加載,可以在用戶需要查看圖片時才加載圖片,避免了不必要的圖片加載,本文給大家介紹了React實現(xiàn)圖片懶加載的常見方式,需要的朋友可以參考下
    2024-01-01

最新評論