鍚浣犳兂鍐欎釜 React - virtual dom

Posted 寰井绗戠殑铚楃墰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了鍚浣犳兂鍐欎釜 React - virtual dom相关的知识,希望对你有一定的参考价值。

澶у濂斤紝鎴戞槸寰井绗戠殑铚楃墰锛岎煇屻€?/p>

涓婁竴绡囨枃绔犱粙缁嶄簡 jsx 鑳屽悗鐨勫疄鐜帮紝浠婂ぉ鏉ヤ粙缁嶄竴涓?virtual dom銆?/p>

濡備綍鏇存柊 dom

鑻ラ噰鐢ㄧ幇鏈夌殑瀹炵幇鏂瑰紡锛屾兂瑕佹洿鏂?dom锛屽彧鑳藉厛鏋勯€犱笉鍚岀殑鑺傜偣鎻忚堪淇℃伅锛屽啀閲嶆柊璋冪敤 render 鏂规硶銆?/p>

鍏堢湅涓€涓緥瀛愶紝璁℃椂鍣ㄦ瘡闅?1s 鍒锋柊椤甸潰銆?/p>

const rootDom = document.getElementById("root");

function tick({
  const time = new Date().toLocaleString();
  const clockElement = <h1>{time}</h1>;
  SLReact.render(clockElement, rootDom);
}

tick();
setInterval(tick, 1000);

杩欎釜渚嬪瓙涓紝姣忕閮戒細璋冪敤涓€娆?render 鏂规硶銆?/p>

鑰屼互鐜版湁鐨勫疄鐜版柟寮忥紝render 鏂规硶涓€绘槸鍦ㄥ線 dom 鏍戜笂娣诲姞鑺傜偣銆傝繖鏍蜂細閫犳垚鑺傜偣涓嶆柇鐨勫鍔狅紝灏卞儚涓嬪浘杩欎釜鏍峰瓙銆?/p>

浣嗘垜浠彲绋嶅井绠€鍗曚慨鏀逛竴涓?render 鐨勫疄鐜帮紝灏嗘坊鍔犳敼鎴愭浛鎹€?/p>

if (!parentDom.lastChild) {
 parentDom.appendChild(dom);     
else {
 parentDom.replaceChild(dom, parentDom.lastChild);    
}

杩欐牱鏀硅繃涔嬪悗锛屾瘮涓婇潰鐨勫疄鐜版柟妗堣濂戒竴鐐广€備絾鏄浜庡鏉傜殑缁撴瀯鏉ヨ锛屼粛鏄€楄垂宸ㄥぇ锛屽洜涓哄湪鎿嶄綔鐪熷疄鐨?dom 鏍戙€?/p>

浣嗗鏋滆瘯鎯虫湁涓€绉嶆柟妗堬紝鍙埛鏂板樊寮傞儴鍒嗭紝閭d箞鎿嶄綔 dom 鏍戠殑鏁堢巼灏嗕細澶уぇ鎻愬崌銆?/p>

閭d箞濡備綍鎵嶈兘寰楀埌鍓嶅悗 dom 鏍戠殑宸紓鍛紵

杩欏氨闇€瑕佺敤鍒颁腑闂村眰锛屼娇鐢ㄩ澶栫殑缁撴瀯鏉ュ瓨鍌ㄧ湡瀹?dom 鏍戠殑缁撴瀯銆傚湪閲嶆柊 render 鐨勬椂鍊欙紝杩涜鏂拌€佸姣旓紝鎵惧嚭宸紓閮ㄥ垎锛屽啀杩涜鏇存柊銆?/p>

杩欑涓棿缁撴瀯绉颁箣涓?virtual dom锛屽彲绠€绉?vdom銆備负浠€涔堝彨鍋氳櫄鎷?dom锛屽洜涓哄畠鍙槸鍐呭瓨涓湡瀹?dom 鏍戠殑瀵圭収銆?/p>

virtual dom

  1. 鍙兂鑰岀煡锛寁dom 涓?dom 浼氭湁涓€绉嶆槧灏勫叧绯汇€倂dom 闇€瑕佽窡鐪熷疄 dom 杩涜鍏宠仈锛岃繖鏍峰氨鍙互鏂逛究鐨勬壘鍒扮湡瀹?dom锛岃繘琛屾搷浣溿€傞偅涔堝湪 vdom 鐨勪俊鎭腑灏变細鍖呭惈 dom銆?/p>

  2. 姝ゅ锛寁dom 杩橀渶鍖呭惈鑺傜偣鎻忚堪淇℃伅锛屼笉鐒舵€庝箞鍋氬姣斿憿锛?/p>

  3. vdom 涔熸槸鏍戠姸缁撴瀯锛岄偅涔堝悓鏍峰寘鍚瓙鑺傜偣銆?/p>

鏍规嵁涓婅堪鍒嗘瀽锛屾垜浠究鍙緱鍒?vdom 鐨勭粨鏋勩€傚畠鍖呮嫭鑺傜偣鎻忚堪淇℃伅銆佸叧鑱旂殑鐪熷疄 dom銆佸瓙 vdom 鑺傜偣銆傛瘡涓?dom 鑺傜偣閮藉搴旂潃涓€涓?vdom 鑺傜偣銆?/p>

褰撳湪鍋?diff 鏃讹紝鏍规嵁鏂版棫鑺傜偣鎻忚堪淇℃伅锛屾壘鍑哄樊寮傞儴鍒嗭紝灏藉彲鑳界殑閲嶇敤 dom锛屽噺灏戝紑閿€銆?/p>

閭e浣曟潵鏋勫缓 vdom 杩涜 diff 鍛紵涓嬮潰鎴戜滑鏉ヤ竴姝ユ鐨勮瑙c€?/p>

vdom 缁撴瀯

铏氭嫙 dom 鑺傜偣淇℃伅鍖呮嫭涓夐儴鍒嗭細

  • 鑺傜偣鎻忚堪淇℃伅
  • 鍏宠仈鐨勭湡瀹?dom
  • 瀛愯櫄鎷?dom 鑺傜偣

瀹冪殑缁撴瀯濡備笅锛?/p>

let vdom = { dom, element, childInstances };

鏍规嵁涔嬪墠鐨?render 鏂规硶锛屽叾瀹炴瘮杈冨鏄撴敼閫犲嚭杩欑缁撴瀯銆傚洜涓哄畠杩斿洖鐨勬槸鐪熷疄 dom锛屾垜浠彧闇€灏嗚繑鍥炰俊鎭慨鏀逛负 virtual dom 鐨勭粨鏋勫氨濂姐€?/p>

鏀归€犺繃绋嬪涓嬶細

  • 鏍规嵁鑺傜偣绫诲瀷鐢熸垚鐪熷疄 dom
  • 鏇存柊 dom 灞炴€?
  • 閫掑綊澶勭悊瀛愯妭鐐?
  • 鑾峰彇瀛愯妭鐐圭湡瀹?dom锛岄€愪釜娣诲姞鍒扮埗鑺傜偣
  • 杩斿洖 virtual dom

浠g爜濡備笅鎵€绀猴細

// virtual dom锛屼繚瀛樼湡瀹炵殑 dom锛宔lement锛宑hildInstance
function instantitate(element{

  const { type, props } = element;
  const isTextElement = type === TEXT_ELEMENT;

 // 鐢熸垚鐪熷疄 dom
  const dom = isTextElement
    ? document.createTextNode("")
    : document.createElement(type);

  // 鏇存柊灞炴€?/span>
  updateDomProperties(dom, [], props);

  // 澶勭悊瀛愯妭鐐?/span>
  const childElements = props.children || [];

 // 鐢熸垚瀛愯櫄鎷?nbsp;dom
  const childInstances = childElements.map(instantitate);

 // 鑾峰彇瀛?nbsp;dom
  const childDoms = childInstances.map((childInstance) => childInstance.dom);

 // 娣诲姞鍒?nbsp;dom 鏍?/span>
  childDoms.forEach((childDom) => dom.appendChild(childDom));

 // 缁勬垚铏氭嫙 dom 缁撴瀯
  const instance = { dom, element, childInstances };

  return instance;
}

鍦ㄥ緱鍒?virtual dom 缁撴瀯鍚庯紝涓嬩竴姝ラ渶瑕佸仛鐨勫氨鏄洿鏂扮湡瀹?dom 鑺傜偣銆?/p>

姝ゆ椂锛宺ender 鏂规硶闇€瑕佽繘琛屾敼閫狅紝鍙樹负姣旇緝鍓嶅悗 vdom 宸紓銆?/p>

let rootInstance = null;

function render(element, parentDom{
  const prevInstance = rootInstance;
  const nextInstance = reconcile(parentDom, prevInstance, element);
  rootInstance = nextInstance;
}

瀹冧富瑕佸伐浣滄槸鍜屼笂涓€涓?virtual dom 瀹炰緥鍋氬姣旓紝鐒跺悗杩涜 dom 鏍戠殑鏇存柊銆?/p>

杩欓噷鎴戜滑灏?diff 鏇存柊鐨勮繃绋嬪彨鍋?reconcile锛屽畠浼氳繑鍥?virtual dom 鑺傜偣銆傚涓嬪浘鎵€绀猴細

鍚浣犳兂鍐欎釜 React - virtual dom

diff 绠€鍗曞鐞?span class="mq-124">

reconcile 鐨勫叆鍙傛湁涓変釜锛屽垎鍒槸鐖?dom 鑺傜偣銆乿dom銆佽妭鐐规弿杩颁俊鎭€?/p>

鍏堟潵鐪嬩竴绉嶇畝鍗曠殑澶勭悊鏂瑰紡锛?/p>

  • 濡傛灉浼犲叆鐨?vdom 涓虹┖锛岃鏄庤繕娌℃湁 dom 鑺傜偣锛岄渶瑕佸皢鐪熷疄 dom 娣诲姞鍒?dom 鏍硅妭鐐逛笂銆?
  • 濡傛灉涓嶄负绌猴紝鍒欑敤鏂扮殑 dom 鑺傜偣鏇挎崲鍘熸湁 dom 鑺傜偣銆?

濡備笅鎵€绀猴細

function reconcile(parentDom, instance, element{
  if (instance == null) {
  // 娣诲姞 dom
    const newInstance = instantiate(element);
    parentDom.appendChild(newInstance.dom);
    return newInstance;
  } else {
  // 鏇挎崲 dom
    const newInstance = instantiate(element);
    parentDom.replaceChild(newInstance.dom, instance.dom);
    return newInstance;
  }
}

涓嶇煡澶у鍙戠幇浜嗘病锛屼笂闈㈢殑澶勭悊涓紝鏃犺鍝鏉′欢涓嬮兘璋冪敤浜?instantiate 鏂规硶鏉ラ噸鏂板垱寤?vdom 缁撴瀯銆?/p>

鑰?instantiate 涓細鍒涘缓鐪熷疄 dom锛岃繖鏍峰湪鑺傜偣绫诲瀷娌″彉鍖栨椂浼氫骇鐢熶笉蹇呰鐨勫紑閿€銆?/p>

閲嶇敤 dom 鑺傜偣

杩欓噷鎴戜滑鍙互绋嶅井浼樺寲涓€涓嬶紝褰撹妭鐐圭被鍨嬩竴鏍锋椂锛屽彲浠ヤ笉鐢ㄩ噸鏂板垱寤?dom 鑺傜偣锛屽鐢ㄥ凡鏈夊氨琛岋紝鐒跺悗鍐嶆洿鏂板睘鎬с€?/p>

濡備笅鎵€绀猴細

function reconcile(parentDom, instance, element{
 if (instance.element.type === element.type) {
    // 澶嶇敤 dom锛屾洿鏂板睘鎬?/span>
    updateDomProperties(instance.dom, instance.element.props, element.props);
    instance.element = element;
    return instance;
  }
}

瀛愯妭鐐?diff

浣嗘槸锛岃繕瀛樺湪涓€涓棶棰橈紝瀛愯妭鐐圭殑 diff 杩樻病鏈夎繘琛屽鐞嗐€?/p>

鍦?React 涓紝瀛愯妭鐐逛細鏈変竴涓澶栫殑灞炴€?key锛屼互瀹冧负鏍囪瘑鏉ュ姣斾箣鍓嶇殑鑺傜偣銆?/p>

杩欓噷锛屾垜浠皢绠€鍗曞鐞嗭紝鍙皢姣忎釜浣嶇疆涓婄殑瀛愯妭鐐逛笌鏂扮殑鑺傜偣淇℃伅杩涜瀵规瘮锛岃繘琛屾柊澧?鏇存柊/鏇挎崲/鍒犻櫎鎿嶄綔銆?/p>

濡備笅鎵€绀猴細

// 瀵瑰瓙鑺傜偣鍋氬鐞?/span>
function reconcileChildren(instance, element{
  const dom = instance.dom;

 // 鍘熸湁 virutal dom
  const childInstances = instance.childInstances;

 // 鏂扮殑鑺傜偣鎻忚堪淇℃伅
  const nextChildElements = element.props.children || [];

  const newChildInstances = [];

  // 鍙栨渶澶х殑锛岃嫢鏂板瓙鑺傜偣鏁?nbsp;< 鍘熻妭鐐规暟锛岄渶绉婚櫎
  const count = Math.max(childInstances.length, nextChildElements.length);
  for (let i = 0; i < count; i++) {
    const childInstance = childInstances[i];
    const childElement = nextChildElements[i];

    const newChildInstance = reconcile(dom, childInstance, childElement);
    newChildInstances.push(newChildInstance);
  }

  return newChildInstances;
}

姣忎釜浣嶇疆涓婄殑瀛愯妭鐐?diff 浠嶇劧浼氳皟鐢ㄥ埌 reconcile 鏂规硶銆?/p>

璇锋敞鎰忥細鏂版棫瀛愯妭鐐圭殑鏁扮洰鍙兘鏄笉涓€鏍风殑銆?/p>

鑻ユ柊鐨勫瓙鑺傜偣鏁扮洰灏忎簬鏃у瓙鑺傜偣鏁帮紝闇€瑕佸垹闄ゆ棫瀛愯妭鐐广€?/p>

鍥犱负閬嶅巻娆℃暟鏄敱鏂版棫鑺傜偣鏁扮洰鏈€澶х殑閭d釜鍐冲畾銆傚綋閬嶅巻娆℃暟瓒呭嚭鏂板瓙鑺傜偣鏁版椂锛岃繖鏃讹紝childElement 涓?null銆?/p>

濡備笅鍥炬墍绀猴細

瀵瑰簲鍒?reconcile 涓殑澶勭悊锛屽綋 element 涓虹┖鏃讹紝鍒犻櫎鐪熷疄 dom 鑺傜偣锛岀劧鍚?vdom 杩斿洖 null銆?/p>

// dom 鏇存柊鎿嶄綔
function reconcile(parentDom, instance, element{
 // 鐪佺暐...
 if (element == null) {
    console.log("remove dom");

    // remove锛岃嫢鏂板瓙鑺傜偣鏁?nbsp;< 鍘熻妭鐐规暟锛岄渶绉婚櫎
    parentDom.removeChild(instance.dom);
    return null;

  } else if (instance.element.type == element.type) {

    console.log("reuse dom");

    // 閲嶇敤鑺傜偣锛屾洿鏂板睘鎬?/span>
    updateDomProperties(instance.dom, instance.element.props, element.props);

  // 瀛愯妭鐐瑰鐞?/span>
    instance.childInstances = reconcileChildren(instance, element);
    instance.element = element;
    return instance;
  }
}

杩欐牱灏卞畬鎴愪簡 dom diff 鐨勭畝鍗曞鐞嗐€?/p>

瀹屾暣浠g爜鍙煡鐪嬶細https://github.com/silan-liu/slreact/tree/master/part3銆?/p>

鎬荤粨

杩欑瘒鏂囩珷涓昏浠嬬粛浜嗗浣曟瀯寤?virutal dom 缁撴瀯锛屼互鍙婅繘琛岀畝鍗曠殑 diff 澶勭悊锛屼互閲嶇敤 dom 鑺傜偣锛屽噺灏戜笉蹇呰鐨勫紑閿€銆?/p>

涓嬩竴绡囧皢浠嬬粛 component 鍜?state 鐨勫疄鐜帮紝鏁鏈熷緟~

鏈€鍚?/h2>

以上是关于鍚浣犳兂鍐欎釜 React - virtual dom的主要内容,如果未能解决你的问题,请参考以下文章

璁╄璁℃ā寮忛涓€浼氬効|鈶犲紑绡囪幏濂栨劅瑷€

鍨冨溇鍥炴敹鍣細浣犳槸浠€涔堝瀮鍦撅紵