24. React源碼之domdiff--多節(jié)點(diǎn)(二)

第三輪遍歷(oldFiber沒遍歷完且newChildren沒遍歷完):

  • 把剩下的oldFiber放入existingChildren中;
  • 聲明lastPlacedIndex變量脖咐,表示不需要移動(dòng)的老節(jié)點(diǎn)的索引;
  • 如果在map中能找到相同key相同type的節(jié)點(diǎn)復(fù)用老fiber困乒,并從map中刪除;
  • 如果在map中找不到相同key相同type的節(jié)點(diǎn)創(chuàng)建新fiber;
  • 如果復(fù)用老fiber举娩,老fiber的索引大于lastPlacedIndex則更新lastPlacedIndex為老fiber的索引;
  • 如果復(fù)用老fiber,老fiber的索引小于lastPlacedIndex則移動(dòng)fiber, lastPlacedIndex不變饰躲;
  • 把map中剩下的fiber全部標(biāo)記為刪除

代碼詳情

  1. main.jsx
function FunctionComponent() {
  const [number, setNumber] = React.useState(0);
  return number === 0 ? (
    <ul key="container" onClick={() => setNumber(number + 1)}>
      <li key="A">A</li>
      <li key="B" id="b">
        B
      </li>
      <li key="C">C</li>
      <li key="D">D</li>
      <li key="E">E</li>
      <li key="F" id="F">
        F
      </li>
    </ul>
  ) : (
    <ul key="container" onClick={() => setNumber(number + 1)}>
      <li key="A">A2</li>
      <li key="C">C2</li>
      <li key="E">E2</li>
      <li key="B" id="b2">
        B2
      </li>
      <li key="G">G</li>
      <li key="D">D2</li>
    </ul>
  );
}
let element = <FunctionComponent />;

const root = createRoot(document.getElementById("root"));
console.log("root", root);
root.render(element);
  1. ReactChildFiber
function placeChild(newFiber, lastPlacedIndex, newIdx) {
    newFiber.index = newIdx;
    if (!shouldTrackSideEffects) {
      return lastPlacedIndex;
    }
    const current = newFiber.alternate;
    if (current !== null) {
      const oldIndex = current.index;
      if (oldIndex < lastPlacedIndex) {
        newFiber.flags |= Placement;
        return lastPlacedIndex;
      } else {
        return oldIndex;
      }
    } else {
      newFiber.flags |= Placement;
      return lastPlacedIndex;
    }
  }

 function mapRemainingChildren(returnFiber, currentFirstChild) {
    const existingChildren = new Map();
    let existingChild = currentFirstChild;
    while (existingChild != null) {
      if (existingChild.key != null) {
        existingChildren.set(existingChild.key, existingChild);
      } else {
        existingChildren.set(existingChild.index, existingChild);
      }
      existingChild = existingChild.sibling;
    }
    return existingChildren;
  }

function updateTextNode(returnFiber, current, textContent) {
    if (current !== null || current.tag !== HostText) {
      const created = createFiberFromText(textContent);
      created.return = returnFiber;
      return created;
    } else {
      const existing = useFiber(current, textContent);
      existing.return = returnFiber;
      return existing;
    }
  }

function updateFromMap(existingChildren, returnFiber, newIdx, newChild) {
    if (
      (typeof newChild === "string" && newChild !== "") ||
      typeof newChild === "number"
    ) {
      const matchedFiber = existingChildren.get(newIdx) || null;
      return updateTextNode(returnFiber, matchedFiber, "" + newChild);
    }
    if (typeof newChild === "object" && newChild !== null) {
      switch (newChild.$$typeof) {
        case REACT_ELEMENT_TYPE: {
          const matchedFiber =
            existingChildren.get(
              newChild.key === null ? newIdx : newChild.key
            ) || null;
          return updateElement(returnFiber, matchedFiber, newChild);
        }
      }
    }
  }

 function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren) {
    let resultingFirstChild = null;
    let previousNewFiber = null;
    let newIdx = 0;
    let oldFiber = currentFirstChild;
    let nextOldFiber = null;
    let lastPlacedIndex = 0;
    ...
    const existingChildren = mapRemainingChildren(returnFiber, oldFiber);
    for (; newIdx < newChildren.length; newIdx++) {
      const newFiber = updateFromMap(
        existingChildren,
        returnFiber,
        newIdx,
        newChildren[newIdx]
      );
      if (newFiber !== null) {
        if (shouldTrackSideEffects) {
          if (newFiber.alternate !== null) {
            existingChildren.delete(
              newFiber.key === null ? newIdx : newFiber.key
            );
          }
        }
        lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
        if (previousNewFiber === null) {
          resultingFirstChild = newFiber;
        } else {
          previousNewFiber.sibling = newFiber;
        }
        previousNewFiber = newFiber;
      }
    }
    if (shouldTrackSideEffects) {
      existingChildren.forEach((child) => deleteChild(returnFiber, child));
    }
    return resultingFirstChild;
  }
domdiff
DOM操作
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市臼隔,隨后出現(xiàn)的幾起案子嘹裂,更是在濱河造成了極大的恐慌,老刑警劉巖躬翁,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焦蘑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盒发,警方通過查閱死者的電腦和手機(jī)例嘱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宁舰,“玉大人拼卵,你說我怎么就攤上這事÷瑁” “怎么了腋腮?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我即寡,道長(zhǎng)徊哑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任聪富,我火速辦了婚禮莺丑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘墩蔓。我一直安慰自己梢莽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布奸披。 她就那樣靜靜地躺著昏名,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阵面。 梳的紋絲不亂的頭發(fā)上轻局,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音膜钓,去河邊找鬼嗽交。 笑死,一個(gè)胖子當(dāng)著我的面吹牛颂斜,可吹牛的內(nèi)容都是我干的夫壁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼沃疮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼盒让!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起司蔬,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤邑茄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后俊啼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肺缕,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年授帕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了同木。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡跛十,死狀恐怖彤路,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芥映,我是刑警寧澤洲尊,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布远豺,位于F島的核電站,受9級(jí)特大地震影響坞嘀,放射性物質(zhì)發(fā)生泄漏躯护。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一姆吭、第九天 我趴在偏房一處隱蔽的房頂上張望榛做。 院中可真熱鬧,春花似錦内狸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至刽严,卻和暖如春昂灵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舞萄。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工眨补, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倒脓。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓撑螺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親崎弃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子甘晤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349