日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
面試官:說說ReactJsx轉(zhuǎn)換成真實DOM過程?

本文轉(zhuǎn)載自微信公眾號「JS每日一題」,作者灰灰。轉(zhuǎn)載本文請聯(lián)系JS每日一題公眾號。

創(chuàng)新互聯(lián)建站主要從事網(wǎng)站制作、網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)井岡山,10年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220

一、是什么

react通過將組件編寫的JSX映射到屏幕,以及組件中的狀態(tài)發(fā)生了變化之后 React會將這些「變化」更新到屏幕上

在前面文章了解中,JSX通過babel最終轉(zhuǎn)化成React.createElement這種形式,例如:

 
 
 
 
  1.  
  2.    
  3.    
 

會被bebel轉(zhuǎn)化成如下:

 
 
 
 
  1. React.createElement( 
  2.   "div", 
  3.   null, 
  4.   React.createElement("img", { 
  5.     src: "avatar.png", 
  6.     className: "profile" 
  7.   }), 
  8.   React.createElement(Hello, null) 
  9. ); 

在轉(zhuǎn)化過程中,babel在編譯時會判斷 JSX 中組件的首字母:

  • 當(dāng)首字母為小寫時,其被認(rèn)定為原生 DOM 標(biāo)簽,createElement 的第一個變量被編譯為字符串
  • 當(dāng)首字母為大寫時,其被認(rèn)定為自定義組件,createElement 的第一個變量被編譯為對象

最終都會通過RenderDOM.render(...)方法進(jìn)行掛載,如下:

 
 
 
 
  1. ReactDOM.render(,  document.getElementById("root")); 

二、過程

在react中,節(jié)點大致可以分成四個類別:

  • 原生標(biāo)簽節(jié)點
  • 文本節(jié)點
  • 函數(shù)組件
  • 類組件

如下所示:

 
 
 
 
  1. class ClassComponent extends Component { 
  2.   static defaultProps = { 
  3.     color: "pink" 
  4.   }; 
  5.   render() { 
  6.     return ( 
  7.        
  8.         

    ClassComponent

     
  9.         {this.props.name}

     
  10.       
 
  •     ); 
  •   } 
  •  
  • function FunctionComponent(props) { 
  •   return ( 
  •      
  •       FunctionComponent 
  •       

    {props.name}

     
  •     
  •  
  •   ); 
  •  
  • const jsx = ( 
  •    
  •     

    xx

     
  •     xxx 
  •      
  •      
  •   
  •  
  • ); 
  • 這些類別最終都會被轉(zhuǎn)化成React.createElement這種形式

    React.createElement其被調(diào)用時會傳?標(biāo)簽類型type,標(biāo)簽屬性props及若干子元素children,作用是生成一個虛擬Dom對象,如下所示:

     
     
     
     
    1. function createElement(type, config, ...children) { 
    2.     if (config) { 
    3.         delete config.__self; 
    4.         delete config.__source; 
    5.     } 
    6.     // ! 源碼中做了詳細(xì)處理,?如過濾掉key、ref等 
    7.     const props = { 
    8.         ...config, 
    9.         children: children.map(child => 
    10.    typeof child === "object" ? child : createTextNode(child) 
    11.   ) 
    12.     }; 
    13.     return { 
    14.         type, 
    15.         props 
    16.     }; 
    17. function createTextNode(text) { 
    18.     return { 
    19.         type: TEXT, 
    20.         props: { 
    21.             children: [], 
    22.             nodeValue: text 
    23.         } 
    24.     }; 
    25. export default { 
    26.     createElement 
    27. }; 

    createElement會根據(jù)傳入的節(jié)點信息進(jìn)行一個判斷:

    • 如果是原生標(biāo)簽節(jié)點, type 是字符串,如div、span
    • 如果是文本節(jié)點, type就沒有,這里是 TEXT
    • 如果是函數(shù)組件,type 是函數(shù)名
    • 如果是類組件,type 是類名

    虛擬DOM會通過ReactDOM.render進(jìn)行渲染成真實DOM,使用方法如下:

     
     
     
     
    1. ReactDOM.render(element, container[, callback]) 

    當(dāng)首次調(diào)用時,容器節(jié)點里的所有 DOM 元素都會被替換,后續(xù)的調(diào)用則會使用 React 的 diff算法進(jìn)行高效的更新

    如果提供了可選的回調(diào)函數(shù)callback,該回調(diào)將在組件被渲染或更新之后被執(zhí)行

    render大致實現(xiàn)方法如下:

     
     
     
     
    1. function render(vnode, container) { 
    2.     console.log("vnode", vnode); // 虛擬DOM對象 
    3.     // vnode _> node 
    4.     const node = createNode(vnode, container); 
    5.     container.appendChild(node); 
    6.  
    7. // 創(chuàng)建真實DOM節(jié)點 
    8. function createNode(vnode, parentNode) { 
    9.     let node = null; 
    10.     const {type, props} = vnode; 
    11.     if (type === TEXT) { 
    12.         node = document.createTextNode(""); 
    13.     } else if (typeof type === "string") { 
    14.         node = document.createElement(type); 
    15.     } else if (typeof type === "function") { 
    16.         node = type.isReactComponent 
    17.             ? updateClassComponent(vnode, parentNode) 
    18.         : updateFunctionComponent(vnode, parentNode); 
    19.     } else { 
    20.         node = document.createDocumentFragment(); 
    21.     } 
    22.     reconcileChildren(props.children, node); 
    23.     updateNode(node, props); 
    24.     return node; 
    25.  
    26. // 遍歷下子vnode,然后把子vnode->真實DOM節(jié)點,再插入父node中 
    27. function reconcileChildren(children, node) { 
    28.     for (let i = 0; i < children.length; i++) { 
    29.         let child = children[i]; 
    30.         if (Array.isArray(child)) { 
    31.             for (let j = 0; j < child.length; j++) { 
    32.                 render(child[j], node); 
    33.             } 
    34.         } else { 
    35.             render(child, node); 
    36.         } 
    37.     } 
    38. function updateNode(node, nextVal) { 
    39.     Object.keys(nextVal) 
    40.         .filter(k => k !== "children") 
    41.         .forEach(k => { 
    42.         if (k.slice(0, 2) === "on") { 
    43.             let eventName = k.slice(2).toLocaleLowerCase(); 
    44.             node.addEventListener(eventName, nextVal[k]); 
    45.         } else { 
    46.             node[k] = nextVal[k]; 
    47.         } 
    48.     }); 
    49.  
    50. // 返回真實dom節(jié)點 
    51. // 執(zhí)行函數(shù) 
    52. function updateFunctionComponent(vnode, parentNode) { 
    53.     const {type, props} = vnode; 
    54.     let vvnode = type(props); 
    55.     const node = createNode(vvnode, parentNode); 
    56.     return node; 
    57.  
    58. // 返回真實dom節(jié)點 
    59. // 先實例化,再執(zhí)行render函數(shù) 
    60. function updateClassComponent(vnode, parentNode) { 
    61.     const {type, props} = vnode; 
    62.     let cmp = new type(props); 
    63.     const vvnode = cmp.render(); 
    64.     const node = createNode(vvnode, parentNode); 
    65.     return node; 
    66. export default { 
    67.     render 
    68. }; 

    三、總結(jié)

    在react源碼中,虛擬Dom轉(zhuǎn)化成真實Dom整體流程如下圖所示:

    其渲染流程如下所示:

    • 使用React.createElement或JSX編寫React組件,實際上所有的 JSX 代碼最后都會轉(zhuǎn)換成React.createElement(...) ,Babel幫助我們完成了這個轉(zhuǎn)換的過程。
    • createElement函數(shù)對key和ref等特殊的props進(jìn)行處理,并獲取defaultProps對默認(rèn)props進(jìn)行賦值,并且對傳入的孩子節(jié)點進(jìn)行處理,最終構(gòu)造成一個虛擬DOM對象
    • ReactDOM.render將生成好的虛擬DOM渲染到指定容器上,其中采用了批處理、事務(wù)等機制并且對特定瀏覽器進(jìn)行了性能優(yōu)化,最終轉(zhuǎn)換為真實DOM

    參考文獻(xiàn)

    https://bbs.huaweicloud.com/blogs/265503)

    https://huang-qing.github.io/react/2019/05/29/React-VirDom/

    https://segmentfault.com/a/1190000018891454


    當(dāng)前名稱:面試官:說說ReactJsx轉(zhuǎn)換成真實DOM過程?
    分享鏈接:http://m.5511xx.com/article/djejhed.html