React入門學習

為了獲得更好的閱讀體驗,請訪問原地址:傳送門

一睬涧、React 簡介


React 是什么

React 是一個起源于 Facebook 的內部項目,因為當時 Facebook 對于市場上所有的 JavaScript MVC 框架都不太滿意旗唁,所以索性就自己寫了一套畦浓,用來架設 Instagram。做出來之后检疫,發(fā)現(xiàn)這套東西還蠻好用的讶请,于是就在 2013 年 5 月開源了

在這里我們需要稍微注意一下 庫(Library)框架(Framework) 的區(qū)別屎媳,React 本身是一個用于構建用戶界面的 JavaScript 庫夺溢,而我們平時所說的 React 框架其實是指的是 React/ React-router 和 React-redux 的結合體,庫和框架的本質區(qū)別體現(xiàn)在于控制權:

  • 「庫」是一個封裝好的特定的集合烛谊,提供給開發(fā)者使用风响,而且是特定于某一方面的集合(方法和函數(shù)),庫沒有控制權丹禀,控制權完全在于使用者本身状勤;
  • 「框架」顧名思義是一套架構,會基于自身的特點向用戶提供一套比較完整的解決方案双泪,如果使用者選定了一套框架持搜,那么就需要根據(jù)框架本身做出一定的適應。

為什么使用 React焙矛?

這是一個非常有趣的問題朵诫,也讓我困惑和苦惱。在筆者還在學校的時候嘗試用 Vue 搭建了一套簡單的博客系統(tǒng)薄扁,學習曲線平滑剪返,讓只會一些基礎 HTML/ CSS 代碼的我通過一段時間學習就能夠上手了,但是學習 React 以來邓梅,進展變得相對緩慢.. 一部分原因是因為 React 創(chuàng)新性的開發(fā)模式以及讓我感到無所適從的 JSX 語法(菜才是原罪)脱盲。

Vue 作者尤雨溪在知乎上回答「Vue 和 React 的優(yōu)點分別是什么?」這個問題的時候提到 :

這里我可以大方地承認日缨,如果多年以后要論歷史地位钱反,React 肯定是高于 Vue 的。事實上匣距,我作為一個開發(fā)者面哥,也是由衷地佩服 Jordan Walke, Sebastian Markbage 這樣的,能從開發(fā)模式層面上提出突破性的新方向的人毅待。

React 從一開始的定位就是提出 UI 開發(fā)的新思路尚卫。當年 Pete Hunt 最開始推廣 React 的時候的一句口號就叫 "Rethinking Best Practices",這樣的定位使得 React 打開了一些全新的思路尸红,吸引了一群喜歡折騰的早期核心用戶吱涉,并在這個基礎上通過社區(qū)迭代孵化出了許多今天被 React 開發(fā)者當作常識的 pattern。這是 React 偉大的地方外里,Vue 里面也有很多地方是直接受到了 React 的啟發(fā)怎爵。React 敢做這樣的嘗試,是因為它是 Facebook盅蝗。這樣的體量的公司鳖链,在 infrastructure 層面獲得質的提升,收益是巨大的墩莫,而且 Facebook 的工程師們足夠聰明又要靠工資吃飯芙委,改變他/她們的習慣并不是什么問題。而對外推廣贼穆,則是一種大公司才有的 “改變業(yè)界” 的底氣题山。

相比「為什么使用 React?」的理由故痊,稱贊 React 的倒是明顯更多一些(React 確實是突破性的開發(fā)模式)顶瞳。

是因為 React 組件化的思想嗎?不是愕秫。我覺得這跟多少跟微服務化之類的概念有點兒類似慨菱,這是屬于一個時代對于計算機工程的思想進步,是對于團隊協(xié)作提出的新一種成熟的解決方案戴甩,也是必然的一種趨勢符喝。當前流行的不管是 Angular/ Vue 還是 React,都天然的支持著組件化的概念甜孤。

那是因為 React 性能出眾嗎协饲?我想也不是畏腕。或許 React 剛出世時因為其獨特高效的虛擬 DOM 設計茉稠,能夠在前端江湖中平步青云描馅,但是現(xiàn)在前端技術都主鍵地趨于成熟(我也不懂,我亂說的..)而线,從很多地方的對比數(shù)據(jù)中铭污,都能夠看得到其實 React 與其他框架的性能差異并不是特別大。并且體現(xiàn)在平時的開發(fā)中膀篮,這樣對比不明顯的速度差異嘹狞,根本沒有多大的用處。

還看到一種觀點誓竿,說 React 適用于構建大型的項目磅网。從我并不多的了解中,我知道 React 體系中天然有著許多的約束烤黍,以及一些不成文的約定知市,這就好像是 SpringBoot 中默認提供給使用者的一些姿勢,天然就有很強的工程性速蕊,加上一些約定俗成的代碼風格 or 歸約嫂丙,這就使得 Java 很適合一些大型的團隊項目。但能不能開發(fā)大型的項目從來都是取決于人规哲,而不是采用了哪種框架跟啤。

所以比較令我信服的理由是(我亂猜的):像 Java 一樣,React 體系足夠成熟唉锌,社區(qū)也非秤绶剩活躍,你遇到的問題很容易在網(wǎng)絡上找到答案袄简,并且也有一些成熟的實踐 or 輪子用以解決各種各樣的問題腥放。而且 React 還有一個比較特別的特性是:你能夠比較無痛地使用 React Native 開發(fā)原生移動應用。

二绿语、React 核心概念


虛擬 DOM(Vitural Document Object Model)

要理解這個「虛擬 DOM」的概念秃症,首先我們就需要知道什么是「DOM」。我們先暫時忘掉什么網(wǎng)頁之類的吕粹,我們想象現(xiàn)在我們需要編寫程序來對下列的 Markdown 文檔進行改變應該怎么做:

# Title
## subtitle - 1
content - 1
## subtitle - 2
content - 2

比如我現(xiàn)在就想要 content - 2 的內容進行改變种柑,那么我就需要一行一行的不斷遍歷直到最后遍歷到它才能進行操作,對內容改變的操作都差不多匹耕,所以如果我想對這個查找的操作進行優(yōu)化聚请,最簡單的想法就是把它樹化以減少高度,增加效率稳其。

DOM 的概念

DOM 是英文 Document Object Model 的縮寫驶赏,即文檔對象模型炸卑。它是一種跨平臺的、獨立于編程語言的 API母市,它把 HTML矾兜、XHTML 或 XML 文檔都當做一個樹結構,而每個節(jié)點視為一個對象患久,這些對象可以被編程語言操作,進而改變文檔的結構浑槽,映射到文檔的顯示蒋失。DOM 最開始的時候是和 JavaScript 交織在一起的,只是后來它們最終演變成了兩個獨立的實體桐玻。DOM 被設計成與特定編程語言相獨立篙挽,盡管絕大部分時候我們都是使用 JavaScript 來操作,但其實其他的語言一樣可以(如 Python)镊靴。

假如有這么一段 HTML 代碼:

<html>
  <head>
    <title>文檔標題</title>
  </head>
  
  <body>
    <a href="">鏈接</a>
    <h1>標題</h1>
  </body>
</html>

那么它最終就應該會是下面這棵樹一樣的結構:

這里不對 DOM 節(jié)點的類型啊方法之類的進行討論铣卡,我們只需要對 DOM 有一個大致的概念就好了。

瀏覽器渲染 DOM 的流程

我們可以簡單了解一下瀏覽器渲染 DOM 的流程:

  1. 解析 HTML 建立 DOM 樹偏竟;
  2. 解析 CSS煮落,并結合 DOM 樹形成 Reander 樹;
  3. 布局 Render 樹(Layout/ reflow)踊谋,確定各節(jié)點的尺寸蝉仇、位置等信息;
  4. 繪制 Render 樹(Paint)殖蚕,繪制頁面像素信息轿衔;
  5. 瀏覽器將各層信息發(fā)給 GPU,GPU 會將各層合成(Composite)睦疫,顯示在屏幕上害驹;

操作 DOM 為什么慢

其實嚴格來說,單純的操作 DOM 并不慢蛤育,說它慢是帶有一定條件的宛官。

想象在一次事件循環(huán)中多次操作 DOM 時,有時希望 JS 代碼中能立刻獲取最新的 DOM 節(jié)點信息缨伊,這時瀏覽器不得不掛起 JS 引擎摘刑,轉而調用 DOM 引擎,計算渲染出最新的 DOM刻坊,以此來獲取最新的 DOM 節(jié)點信息枷恕,接著再重新激活 JS 引擎 繼續(xù)后續(xù)的操作。

可以預見谭胚,上述操作不僅需要多次進行引擎的切換徐块,還需要多次計算布局未玻,重新繪制 DOM。事實上paint是一個耗時的過程胡控,然而layout是一個更耗時的過程扳剿,我們無法確定layout一定是自上而下或是自下而上進行的,甚至一次layout會牽涉到整個文檔布局的重新計算昼激。

但是layout是肯定無法避免的庇绽,所以我們主要是要最小化layout的次數(shù)。

所以橙困,降低引擎切換頻率瞧掺、減小 DOM 變更規(guī)模才是 DOM 性能優(yōu)化方案的關鍵!

Virtual DOM 算法步驟

虛擬 DOM 正是解決了上述問題凡傅,它的本質就是用 JS 對象來模擬出我們真實的 DOM 樹辟狈,它的算法大致如下:

  1. 用 JavaScript 對象映射形成 DOM 樹的結構,然后用這個樹構建一個真正的 DOM 樹夏跷,插到文檔當中哼转;
  2. 當狀態(tài)變更的時候,重新構造一棵新的對象樹壹蔓,然后用新的樹和舊的樹進行比較(Diff 算法),記錄兩棵樹差異硼莽;
  3. 把第二步中所記錄的差異應用到步驟一所構建的真正的 DOM 樹上,視圖就更新懂鸵。

虛擬 DOM 和真實 DOM 的區(qū)別

我們由此可以對比出兩者的不同:

  1. 改變多個狀態(tài)偏螺,影響多個節(jié)點布局時匆光,只是頻繁的修改了內存中的 JS 對象,然后一次性比較并修改真實 DOM 中需要改的部分终息,最后在真實 DOM 中進行排版與重繪,減少過多 DOM 節(jié)點排版與重繪損耗周崭;
  2. 真實 DOM 頻繁排版與重繪的效率是相當?shù)偷模?/li>
  3. 虛擬 DOM 有效降低大面積(真實 DOM 節(jié)點)的重繪與排版柳譬,因為最終與真實 DOM 比較差異续镇,可以只渲染局部(同2);

使用虛擬DOM的損耗計算:

總損耗 = 虛擬DOM增刪改 + (與Diff算法效率有關)真實DOM差異增刪改 + (較少的節(jié)點)排版與重繪

直接使用真實DOM的損耗計算:

總損耗 = 真實DOM完全增刪改 + (可能較多的節(jié)點)排版與重繪

Diff 算法

虛擬 DOM 的核心在于 Diff,它自動幫你計算那些應該調整的制跟,然后只修改應該被調整的區(qū)域,省下的不是運行速度這種 "小速度"雨膨,而是開發(fā)速度/ 維護速度/ 邏輯簡練程度等 "總體速度"。

但虛擬 DOM 快也是在相對條件下的聊记,這里引用 @尤雨溪大大在知乎問題《網(wǎng)上都說操作真實 DOM 慢撒妈,但測試結果卻比 React 更快排监,為什么?》上回答的一句話吧:

不要天真地以為 Virtual DOM 就是快社露,diff 不是免費的,batching 么 MVVM 也能做峭弟,而且最終 patch 的時候還不是要用原生 API。在我看來 Virtual DOM 真正的價值從來都不是性能脱拼,而是它 1) 為函數(shù)式的 UI 編程方式打開了大門;2) 可以渲染到 DOM 以外的 backend熄浓,比如 ReactNative。

Diff 大致可以分為三種類型:

  • Tree Diff: 新舊兩棵 DOM 樹赌蔑,逐層對比的過程俯在,就是 Tree Diff娃惯,當整顆DOM逐層對比完畢,則所有需要被按需更新的元素趾浅,必然能夠找到;
  • Component Diff: 在進行 Tree Diff 的時候皿哨,每一層中浅侨,組件級別的對比证膨,叫做 Component Diff:
    • 如果對比前后,組件的類型相同,則暫時認為此組件不需要被更新挨决;
    • 如果對比前后,組件類型不同脖祈,則需要移除舊組件肆捕,創(chuàng)建新組件盖高,并追加到頁面上;
  • Element Diff: 在進行組件對比的時候喻奥,如果兩個組件類型相同,則需要進行元素級別的對比撞蚕,這叫做 Element Diff润梯;

三甥厦、Hello World


使用 React 的網(wǎng)頁源碼,結構大致如下(可以直接運行):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Hello React!</title>
    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>

<div id="example"></div>
<script type="text/babel">
    ReactDOM.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
    );
</script>

</body>
</html>

上面代碼有兩個地方需要注意刀疙。首先,最后一個 <script> 標簽的 type 屬性為 text/babel 谦秧。這是因為 React 獨有的 JSX 語法竟纳,跟 JavaScript 不兼容疚鲤。凡是使用 JSX 的地方,都要加上 type="text/babel" 石咬。

其次揩悄,上面代碼一共用了三個庫: react.js 鬼悠、react-dom.jsBrowser.js ,它們必須首先加載焕窝。其中,react.js是 React 的核心庫它掂,react-dom.js 是提供與 DOM 相關的功能巴帮,Browser.js 的作用是將 JSX 語法轉為 JavaScript 語法,這一步很消耗時間榕茧,實際上線的時候垃沦,應該將它放到服務器完成用押。

$ babel src --out-dir build

上面命令可以將 src 子目錄的 js 文件進行語法轉換,轉碼后的文件全部放在 build 子目錄蜻拨。

ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用于將模板轉為 HTML 語言缎讼,并插入指定的 DOM 節(jié)點收夸。

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('example')
);

上面代碼將一個 h1 標題血崭,插入 example 節(jié)點,運行結果如下:

JSX 語法

上一節(jié)的代碼夹纫, HTML 語言直接寫在 JavaScript 語言之中,不加任何引號捷凄,這就是 JSX 的語法,它允許 HTML 與 JavaScript 的混寫围来。我們先來看以下一段代碼:

const element = <h1>Hello, world!</h1>;

與瀏覽器的 DOM 元素不同跺涤,React 當中的元素事實上是普通的對象,React DOM 可以確保 瀏覽器 DOM 的數(shù)據(jù)內容與 React 元素保持一致监透。要將 React 元素渲染到根 DOM 節(jié)點中桶错,我們通過把它們都傳遞給 ReactDOM.render() 的方法來將其渲染到頁面上:

var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));

JSX 看起來類似 HTML ,你也可以在上面代碼中嵌套多個 HTML 標簽胀蛮,但是需要使用一個 div 元素包裹它院刁。

JavaScript 表達式

我們可以在 JSX 中使用 JavaScript 表達式。表達式寫在花括號 {} 中粪狼。實例如下:

ReactDOM.render(
    <div>
      <h1>{1+1}</h1>
    </div>
    ,
    document.getElementById('example')
);

在 JSX 中不能使用 if else 語句退腥,但可以使用 conditional (三元運算) 表達式來替代再榄。以下實例中如果變量 i 等于 1 瀏覽器將輸出 true, 如果修改 i 的值狡刘,則會輸出 false.

ReactDOM.render(
    <div>
      <h1>{i == 1 ? 'True!' : 'False'}</h1>
    </div>
    ,
    document.getElementById('example')
);

樣式

React 推薦使用內聯(lián)樣式困鸥。我們可以使用 camelCase 語法來設置內聯(lián)樣式. React 會在指定元素數(shù)字后自動添加 px 。以下實例演示了為 h1 元素添加 myStyle 內聯(lián)樣式:

var myStyle = {
    fontSize: 100,
    color: '#FF0000'
};
ReactDOM.render(
    <h1 style = {myStyle}>菜鳥教程</h1>,
    document.getElementById('example')
);

注釋

注釋需要寫在花括號中,實例如下:

ReactDOM.render(
    <div>
    <h1>菜鳥教程</h1>
    {/*注釋...*/}
     </div>,
    document.getElementById('example')
);

數(shù)組

JSX 允許在模板中插入數(shù)組澜术,數(shù)組會自動展開所有成員:

var arr = [
  <h1>菜鳥教程</h1>,
  <h2>學的不僅是技術艺蝴,更是夢想鸟废!</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

參考資料


  1. http://www.ruanyifeng.com/blog/2015/03/react.html - React 入門實例教程 - 阮一峰
  2. http://www.reibang.com/p/60100985dd7f - 前端框架與庫的區(qū)別
  3. https://www.zhihu.com/question/301860721/answer/545031906 - Vue 和 React 的優(yōu)點分別是什么猜敢?
  4. https://zhuanlan.zhihu.com/p/22184194 - 你真的理解 DOM 了嗎?
  5. https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model/Introduction - DOM 概述
  6. https://blog.huteming.site/posts/e0c41c5f/ - 為什么說虛擬DOM更快

按照慣例黏一個尾巴:

歡迎轉載侮攀,轉載請注明出處锣枝!
獨立域名博客:wmyskxz.com
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關注公眾微信號:wmyskxz
分享自己的學習 & 學習資料 & 生活
想要交流的朋友也可以加qq群:3382693

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市兰英,隨后出現(xiàn)的幾起案子撇叁,更是在濱河造成了極大的恐慌,老刑警劉巖畦贸,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陨闹,死亡現(xiàn)場離奇詭異,居然都是意外死亡薄坏,警方通過查閱死者的電腦和手機趋厉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胶坠,“玉大人君账,你說我怎么就攤上這事∩蛏疲” “怎么了乡数?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長闻牡。 經(jīng)常有香客問我净赴,道長,這世上最難降的妖魔是什么罩润? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任玖翅,我火速辦了婚禮,結果婚禮上割以,老公的妹妹穿的比我還像新娘金度。我一直安慰自己,他們只是感情好严沥,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布审姓。 她就那樣靜靜地躺著,像睡著了一般祝峻。 火紅的嫁衣襯著肌膚如雪魔吐。 梳的紋絲不亂的頭發(fā)上扎筒,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音酬姆,去河邊找鬼嗜桌。 笑死,一個胖子當著我的面吹牛辞色,可吹牛的內容都是我干的骨宠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼相满,長吁一口氣:“原來是場噩夢啊……” “哼层亿!你這毒婦竟也來了?” 一聲冷哼從身側響起立美,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤匿又,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后建蹄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碌更,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年洞慎,在試婚紗的時候發(fā)現(xiàn)自己被綠了痛单。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡劲腿,死狀恐怖旭绒,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情焦人,我是刑警寧澤快压,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站垃瞧,受9級特大地震影響,放射性物質發(fā)生泄漏坪郭。R本人自食惡果不足惜个从,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望歪沃。 院中可真熱鬧嗦锐,春花似錦、人聲如沸沪曙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽液走。三九已至碳默,卻和暖如春贾陷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嘱根。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工髓废, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人该抒。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像冈爹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內容