javascript
深入理解React(一)JSX与虚拟DOM
初衷
使用 React 有一段時間了, 一直想找個時間寫一個 React 的系列文章。忙里抽閑,完成了第一篇。寫這系列文章的初衷是總結(jié)這段時間的技術(shù)學(xué)習(xí),以及給那些想學(xué)習(xí) React 的同學(xué)們一點(diǎn)幫助。我會盡量以通俗易懂的語言闡述我對 React 的理解,希望能照顧到更多的新手。相信大家應(yīng)該都明白一個道理,最能夠帶領(lǐng)你進(jìn)步的,并不是比你強(qiáng)很多很多的大牛,而是剛好比你走得快那么一步的腳印。
為什么是React
這是2018年現(xiàn)代前端框架的使用情況統(tǒng)計(jì),圖片來自JavaScript 如日中天,2018趨勢報(bào)告來啦!,數(shù)據(jù)僅供參考??梢钥吹竭@是個前端框架三足鼎立的時代,選擇 React 并不是因?yàn)槠渌蚣懿粔蚝?#xff0c;而是 React 本身有其獨(dú)特的魅力,吸引著開發(fā)者的聚集。就好比喜歡一個人,并不是因?yàn)槠渌瞬缓貌畔矚g他,而是被他獨(dú)特的魅力所吸引才產(chǎn)生了感情。所以對新手來說,大可不必太過糾結(jié)于框架的選擇,框架只是個幫助我們開發(fā)的工具而已。你只需要知道,React 本身足夠強(qiáng)大,能夠讓你在大前端的世界里走的更遠(yuǎn)!Hello World
我們從最簡單的 Hello World 開始,進(jìn)入 React 的世界,使用的是最新的 React 16版本。
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title> </head><body><div id="root"></div>// 引入react及react-dom庫<script src="https://unpkg.com/react@16/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>// 引入babel<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>// 在babel編譯的環(huán)境下執(zhí)行<script type="text/babel">const vDom = <h1>Hello World</h1>const root = document.getElementById('root')ReactDOM.render(vDom, root)</script> </body></html> 復(fù)制代碼在使用 React 之前,我們需要先引入 React 相關(guān)的 js 庫。
- react.development.js 這是 React 的核心庫,用于構(gòu)建頁面 UI
- react-dom.development.js 這是 React 的 DOM 相關(guān)操作庫,可以將你構(gòu)建的 UI 渲染到瀏覽器中
除此之外,還需引入 babel 進(jìn)行語法解析轉(zhuǎn)換。
我們來詳細(xì)解析下上面的 demo,其實(shí) script 標(biāo)簽中一共就寫了3句代碼,但其中包含了 React 的核心知識點(diǎn)——虛擬 DOM 和 JSX 。
<script type="text/babel">const vDom = <h1>Hello World</h1>const root = document.getElementById('root')ReactDOM.render(vDom, root) </script> 復(fù)制代碼JSX
JSX 是 React 的靈魂,全稱 JavaScript XML。顧名思義,它可以讓你在 JS 中使用 XML 標(biāo)記的方式去直接聲明界面的 DOM,這是 React 獨(dú)有的語法糖。
請看 HelloWorld 的例子
const vDom = <h1>Hello World</h1> // 創(chuàng)建h1標(biāo)簽,右邊千萬不能加引號 const root = document.getElementById('root') // 找到<div id="root"></div>節(jié)點(diǎn) ReactDOM.render(vDom, root) // 把創(chuàng)建的h1標(biāo)簽渲染到root節(jié)點(diǎn)上 復(fù)制代碼這里我們在 JS 里直接創(chuàng)建了一個<h1>Hello World</h1>標(biāo)簽,并賦值給 vDom,這就是 JSX 語法。
如果我們將 react 庫的引入注釋掉
ReactDOM.render()這個是 react-dom 庫中的方法,用于將你創(chuàng)建好的 HTML 模板(虛擬 DOM 節(jié)點(diǎn))插入到某個節(jié)點(diǎn)上,并渲染到頁面上。第一個參數(shù)是 HTML 模板,第二個參數(shù)是指定的 DOM 節(jié)點(diǎn)。
在上述 JSX 語法中有幾個值得注意的地方:
- 右邊的 h1 標(biāo)簽千萬不能加引號。如果加上引號的,JS 引擎會將其解釋為字符串類型。其實(shí)從本質(zhì)來說,<h1>Hello World</h1>這是一個對象,叫做虛擬 DOM 對象,后面會講到。
- <script> 標(biāo)簽的 type 屬性為 text/babel。由于使用了 JSX 這種特殊的語法,我們不能再像往常一樣,使用<script type="text/javascript">來解析 JSX,而要借助 babel 來進(jìn)行解析、轉(zhuǎn)換成 JS。
- 將 JSX 語法轉(zhuǎn)為 JavaScript 語法,這一步很消耗時間。所以現(xiàn)在前端項(xiàng)目,都會使用工作流的形式來構(gòu)建,不會在 html 頁面中直接引入 react、寫 js 代碼等等。
簡單來說,就是 JSX 賦予我們在 JS 中直接創(chuàng)建 HTML 標(biāo)簽的能力,因?yàn)?HTML 標(biāo)簽實(shí)在是太弱小了。
當(dāng)然我們也可以不使用 JSX 的語法創(chuàng)建 DOM 節(jié)點(diǎn),直接使用 React 給我們提供的普通 JS 寫法,React.createElement()API 來創(chuàng)建。
可以看到和之前的 JSX 寫法const vDom = <h1>Hello World</h1>效果是一樣的
在使用React.createElement()這種寫法時,我們并不需要用 babel 進(jìn)行解析,因?yàn)檫@本身就是 JS 的語法,JS 引擎可以解析。 其實(shí)本質(zhì)上,JSX 就是為了簡化直接調(diào)用React.createElement() API 的一顆語法糖而已,他執(zhí)行最終會被 babel 解析轉(zhuǎn)換為React.createElement()的形式,所以推薦使用 JSX 的語法來創(chuàng)建頁面的 UI(也就是 HTML 的一些 DOM)。JSX的優(yōu)點(diǎn)
- 類 XML 語法結(jié)構(gòu)清晰
- 增強(qiáng) JS 語義
- 屏蔽 DOM 操作
- ···
我們以前在操作時,需要經(jīng)過以下流程
創(chuàng)建節(jié)點(diǎn) -> 找到插入位置 -> 插入節(jié)點(diǎn),若是還有子節(jié)點(diǎn),還需要繼續(xù)添加,一切都需要手動實(shí)現(xiàn)。
而使用 React 的 JSX 語法只需要const vDom = xxx 然后ReactDOM.render(vDom, root)就可以。
換句話說,以前都是過程式操作,你不僅知道要做什么,還需要自己手動去實(shí)現(xiàn)。而現(xiàn)在變成了聲明式操作,就好比在下命令一樣,你只需要下命令創(chuàng)建怎樣的 DOM 節(jié)點(diǎn),然后下命令插入,中間的過程全部都由 React 框架幫你自動實(shí)現(xiàn),讓開發(fā)者可以完全屏蔽 DOM 的操作。
JSX基本語法規(guī)則
- 遇到 HTML 標(biāo)簽(以 < 開頭),就用 HTML 規(guī)則解析
- 遇到代碼塊{}或括號(),就用 JavaScript 規(guī)則解析
我們把 Hello World 的例子提升下
<script type="text/babel">let title = 'Hello World'const vDom = (<div><h1>{title}</h1></div>)const root = document.getElementById('root')ReactDOM.render(vDom, root) </script> 復(fù)制代碼上述代碼在執(zhí)行時,當(dāng)遇到<div>的左箭頭括號時,使用 HTML 的解析規(guī)則,當(dāng)遇到{title}時,采用 JS 的規(guī)則解析,也就是獲取變量 title 的值。值得一提的是,如果需要創(chuàng)建嵌套的 HTML 結(jié)構(gòu),推薦使用()括號括起來。
虛擬DOM
- 我們在寫前端頁面時,手動操作 DOM,繁瑣又容易出錯,在大規(guī)模應(yīng)用下維護(hù)起來也很困難。
- 并且每次修改 DOM,瀏覽器的 DOM 樹都需要重繪重排,效率十分低下。
- 既然 DOM 手動操作太繁瑣且效率低下,那就在每次狀態(tài)更新時重新渲染整個頁面
- 每次都重新渲染整個頁面效率十分低下,所以就加上一個虛擬 DOM
- 每次修改時,先在虛擬 DOM 上更新,最后在批量更新整個頁面,這樣頁面只需要一次大的更新,效率很高
虛擬 DOM 是在 DOM 的基礎(chǔ)上建立的一個抽象層,我們對 DOM 中的數(shù)據(jù)和狀態(tài)所做的任何改動,都會被自動且高效的同步到虛擬 DOM,最后再批量同步到 DOM 中。React 會在內(nèi)存中維護(hù)一個虛擬 DOM 樹,當(dāng)我們對這個樹進(jìn)行讀或?qū)懙臅r候,實(shí)際上是對虛擬 DOM 進(jìn)行的。當(dāng)數(shù)據(jù)變化時,React 會自動更新虛擬 DOM 樹,然后拿新的虛擬 DOM 樹和舊的虛擬 DOM 樹進(jìn)行對比(當(dāng)中有 DOM diff算法,這個之后再說),把不同的虛擬節(jié)點(diǎn)放到一個隊(duì)列里,最終在渲染時一次批量更新這些隊(duì)列中的虛擬節(jié)點(diǎn)到真實(shí) DOM 中,這是對 DOM 渲染效率上的一個質(zhì)的提升。
一點(diǎn)小結(jié)
React 以 JS 為中心,以 JSX 的獨(dú)特語法糖將"HTML"放到了 JS 里,而 JS 遠(yuǎn)比 HTML 要強(qiáng)大。因此,與其增強(qiáng) HTML 讓其擁有邏輯,不如增強(qiáng) JS 讓其支持標(biāo)簽化,這樣一來既豐富了 JS 操控領(lǐng)域,又提升了頁面渲染的性能。所以,你若是新手也沒關(guān)系,只要你 JS 能力足夠強(qiáng),相信一定能在 React 的世界里策馬奔騰!
最后推薦幾個 React 的社區(qū)
React 官方文檔:react.docschina.org/
React China:react-china.org/
React 開源中國社區(qū):www.oschina.net/translate/t…
我的 github 地址:github.com/FightingHao
如果有什么不懂的地方,歡迎評論,大家一起探討 React 有關(guān)的知識!
總結(jié)
以上是生活随笔為你收集整理的深入理解React(一)JSX与虚拟DOM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM基础系列第14讲:JVM参数之GC
- 下一篇: CommonJS规范(转)