成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:說(shuō)說(shuō)React Jsx轉(zhuǎn)換成真實(shí)DOM過(guò)程?

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

[[414295]]

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

一、是什么

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

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

  1. <div> 
  2.   <img src="avatar.png" className="profile" /> 
  3.   <Hello /> 
  4. </div> 

 

 

會(huì)被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)化過(guò)程中,babel在編譯時(shí)會(huì)判斷 JSX 中組件的首字母:

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

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

  1. ReactDOM.render(<App />,  document.getElementById("root")); 

二、過(guò)程

在react中,節(jié)點(diǎn)大致可以分成四個(gè)類(lèi)別:

  • 原生標(biāo)簽節(jié)點(diǎn)
  • 文本節(jié)點(diǎn)
  • 函數(shù)組件
  • 類(lèi)組件

如下所示:

  1. class ClassComponent extends Component { 
  2.   static defaultProps = { 
  3.     color: "pink" 
  4.   }; 
  5.   render() { 
  6.     return ( 
  7.       <div className="border"
  8.         <h3>ClassComponent</h3> 
  9.         <p className={this.props.color}>{this.props.name}</p> 
  10.       </div> 
  11.     ); 
  12.   } 
  13.  
  14. function FunctionComponent(props) { 
  15.   return ( 
  16.     <div className="border"
  17.       FunctionComponent 
  18.       <p>{props.name}</p> 
  19.     </div> 
  20.   ); 
  21.  
  22. const jsx = ( 
  23.   <div className="border"
  24.     <p>xx</p> 
  25.     <a href="https://www.xxx.com/">xxx</a> 
  26.     <FunctionComponent name="函數(shù)組件" /> 
  27.     <ClassComponent name="類(lèi)組件" color="red" /> 
  28.   </div> 
  29. ); 

這些類(lèi)別最終都會(huì)被轉(zhuǎn)化成React.createElement這種形式

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

  1. function createElement(type, config, ...children) { 
  2.     if (config) { 
  3.         delete config.__self; 
  4.         delete config.__source; 
  5.     } 
  6.     // ! 源碼中做了詳細(xì)處理,⽐如過(guò)濾掉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會(huì)根據(jù)傳入的節(jié)點(diǎn)信息進(jìn)行一個(gè)判斷:

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

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

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

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

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

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

  1. function render(vnode, container) { 
  2.     console.log("vnode", vnode); // 虛擬DOM對(duì)象 
  3.     // vnode _> node 
  4.     const node = createNode(vnode, container); 
  5.     container.appendChild(node); 
  6.  
  7. // 創(chuàng)建真實(shí)DOM節(jié)點(diǎn) 
  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->真實(shí)DOM節(jié)點(diǎn),再插入父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. // 返回真實(shí)dom節(jié)點(diǎn) 
  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. // 返回真實(shí)dom節(jié)點(diǎn) 
  59. // 先實(shí)例化,再執(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)化成真實(shí)Dom整體流程如下圖所示:

其渲染流程如下所示:

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

 

責(zé)任編輯:武曉燕 來(lái)源: JS每日一題
相關(guān)推薦

2021-06-29 09:47:34

ReactSetState機(jī)制

2021-06-30 07:19:36

React事件機(jī)制

2021-08-02 08:34:20

React性能優(yōu)化

2021-09-14 07:06:13

React項(xiàng)目TypeScript

2024-03-05 10:33:39

AOPSpring編程

2024-08-22 10:39:50

@Async注解代理

2024-05-30 08:04:20

Netty核心組件架構(gòu)

2021-07-07 08:36:45

React應(yīng)用場(chǎng)景

2021-08-03 07:51:43

React項(xiàng)目面試

2024-02-29 16:49:20

volatileJava并發(fā)編程

2025-04-08 00:00:00

@AsyncSpring異步

2024-11-19 15:13:02

2023-12-27 18:16:39

MVCC隔離級(jí)別幻讀

2025-04-16 00:00:01

JWT客戶(hù)端存儲(chǔ)加密令

2024-08-29 16:30:27

2024-08-12 17:36:54

2021-05-19 08:40:36

DNS 協(xié)議查詢(xún)

2021-08-03 08:41:18

SQLMysql面試

2021-07-13 07:52:03

ReactHooks組件

2024-02-20 08:13:35

類(lèi)加載引用Class
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 99精品国产一区二区青青牛奶 | 日韩日韩日韩日韩日韩日韩日韩 | 国产精品一区二区在线 | 人人干人人干人人干 | 午夜一区二区三区视频 | 久久一区二区三区四区 | 精品日韩在线 | 四虎在线观看 | 国产亚洲一区二区三区在线观看 | 国产欧美一区二区三区另类精品 | 欧美一区2区三区3区公司 | 国产精品成人久久久久a级 久久蜜桃av一区二区天堂 | 久久久久一区二区三区 | 免费一级做a爰片久久毛片潮喷 | 亚洲一区成人 | 99久久久无码国产精品 | 国产国产精品久久久久 | 黄色国产区 | 日韩精品1区2区3区 国产精品国产成人国产三级 | 精品三级在线观看 | www视频在线观看 | 久久久久久电影 | 亚洲国产欧美在线 | 国产午夜精品久久久久 | 91porn成人精品 | 精品国产一区二区三区久久影院 | 亚洲一区免费视频 | 久久久久国产一区二区三区四区 | 久久福利电影 | 91在线视频免费观看 | 国产精品视频网站 | 亚洲精品免费在线 | 美女视频h | 中文字幕免费 | 91在线观看免费 | 日本五月婷婷 | 色在线免费视频 | 男女激情网站免费 | 国产精品1区2区 | 亚洲激情在线 | 欧美黑人一区二区三区 |