本章內(nèi)容
- 多頁應(yīng)用開發(fā)模式的缺點(diǎn)
- 單頁應(yīng)用開發(fā)模式的優(yōu)點(diǎn)
- 單頁應(yīng)用開發(fā)模式的主要問題
- React 如何解決單頁應(yīng)用開發(fā)模式中的問題
今天的 Web 應(yīng)用程序除了外觀比過去更好看以外符隙,應(yīng)用程序的架構(gòu)和創(chuàng)建方式已經(jīng)和過去有很大的不同资溃。我們來看看如下的應(yīng)用程序:
這是一個簡單的商品目錄瀏覽應(yīng)用程序,它和這種類型的其它應(yīng)用程序一樣,通常包含一個主頁、一個搜索結(jié)果頁粟瞬、一個詳情頁等等。
一、老式的多頁應(yīng)用程序設(shè)計(jì)
如果幾年前我們做過這種應(yīng)用程序详炬,可能會采用包含多個單頁面的方式,即多頁應(yīng)用模式寞奸。頁面流可能會像下面這樣:
在多頁應(yīng)用模式下呛谜,對于大多數(shù)改變頁面顯示的行為,Web 應(yīng)用會導(dǎo)航到一個完全不同的頁面枪萄。用戶會看到原頁面被銷毀隐岛,然后出來一個新頁面,這種用戶體驗(yàn)很不盡人意瓷翻。這對如何維護(hù)應(yīng)用程序的狀態(tài)有很大影響聚凹,除了通過cookie和一些服務(wù)端機(jī)制來保存用戶數(shù)據(jù),基本上就不用管別的了逻悠。
二元践、新派的單頁應(yīng)用程序
今天,需要在單個頁面之間導(dǎo)航的 多頁 Web 應(yīng)用模型已經(jīng)過時(shí)了⊥耍現(xiàn)代的應(yīng)用程序趨向于采用單頁應(yīng)用(SPA)模型单旁。這種模型下,我們不需要導(dǎo)航到不同的頁面饥伊,甚至不需要重新加載一個頁面象浑。應(yīng)用的不同視圖被加載和卸載到相同頁面本身。
在單頁開發(fā)模式下琅豆,上面的應(yīng)用看起來應(yīng)該是下面這樣子:
當(dāng)用戶與應(yīng)用程序交互時(shí)愉豺,我們用數(shù)據(jù)和 HTML 替換紅色虛線的內(nèi)容,從而帶來更流式的體驗(yàn)茫因。我們甚至可以用很多視覺技術(shù)讓新內(nèi)容很好地過渡蚪拦,而這種很酷的技術(shù)以前只在移動設(shè)備或者桌面應(yīng)用中才有。這類效果在多個頁面中導(dǎo)航時(shí)幾乎是不可能的冻押。
如果以前你沒有聽說過單頁應(yīng)用驰贷,這一切聽起來就有點(diǎn)瘋狂。但是你很可能不知不覺遇到過一些單頁應(yīng)用洛巢。如果曾經(jīng)用過 Gmail括袒、Facebook、Instagram稿茉、Twitter 等流行 Web 應(yīng)用锹锰,那么你實(shí)際上就是在用單頁應(yīng)用芥炭。在所有這些應(yīng)用中,內(nèi)容是動態(tài)顯示恃慧,不需要刷新或者導(dǎo)航到不同的頁面园蝠。
講了這么多,搞得好像這些單頁應(yīng)用很復(fù)雜一樣糕伐。事實(shí)上并非完全如此∨樽粒現(xiàn)在 JavaScript 以及大量第三方框架和庫都已經(jīng)有了很大提升,創(chuàng)建單頁應(yīng)用從沒有像現(xiàn)在這樣簡單過良瞧。但是陪汽,這并不意味著沒有提升的空間。
在創(chuàng)建單頁應(yīng)用時(shí)褥蚯,有時(shí)我們會遇到三個主要的問題:
- 在單頁應(yīng)用中挚冤,我們的大部分時(shí)間會花在保持?jǐn)?shù)據(jù)與 UI 同步上。例如赞庶,如果用戶加載新的內(nèi)容训挡,我們要顯式清除搜索字段嗎?是否讓一個導(dǎo)航元素上的活動標(biāo)簽依然可見歧强?哪個元素要在頁面上保留澜薄,哪個應(yīng)該銷毀?這些都是單頁應(yīng)用獨(dú)有的問題摊册。而在老式多頁應(yīng)用模式中肤京,這從來就不是問題,因?yàn)樵诙囗搼?yīng)用模式下在頁面之間導(dǎo)航時(shí)茅特,UI 中的一切都會被銷毀忘分,然后又重建。
- DOM 操作很慢很慢白修。手動查詢元素妒峦、添加子節(jié)點(diǎn)、刪除子樹兵睛、執(zhí)行其它 DOM 操作肯骇,這些都是在瀏覽器中所做的最慢的事情。然而祖很,不幸的是累盗,在單頁應(yīng)用中,我們要做很多這種事情突琳。要響應(yīng)用戶行為以及顯示新內(nèi)容,就不得不操作 DOM符相。
- 處理 HTML 模板會很痛苦拆融。在單頁應(yīng)用中導(dǎo)航蠢琳,實(shí)際上就是處理 HTML 文檔片段。這些 HTML 文檔片段用來表示要顯示的內(nèi)容镜豹,經(jīng)常被稱為模板(template)傲须。要處理模板,將內(nèi)容在同一頁面中顯示出來趟脂,我們就得用 JavaScript 來操作模板泰讽,用數(shù)據(jù)來填充模板,這樣代碼很快變得很復(fù)雜昔期。更糟糕是已卸,不同的框架,模板的語法以及與數(shù)據(jù)交互的方式有很大不同硼一。例如累澡,如下是 Mustache 中的模板示例:
var view = {
title: "Joe",
calc: function () {
return 2 + 4;
}
};
var output = Mustache.render("{{title}} spends {{calc}}", view);
有時(shí)你的模板可能看起來有點(diǎn)像干凈的 HTML,有時(shí)你的模板可能充滿了莫名其妙的設(shè)計(jì)用來幫助映射 HTML 元素到某些數(shù)據(jù)的自定義標(biāo)簽般贼。
盡管有這些缺點(diǎn)愧哟,單頁應(yīng)用程序并不是到處都是。單頁應(yīng)用只是目前的一部分哼蛆,并且會徹底地構(gòu)成未來web 應(yīng)用創(chuàng)建的方式蕊梧。這并不意味著我們不得不容忍這些缺點(diǎn)。為解決這腮介。肥矢。。萤厅。
三橄抹、遇到 React
Facebook 和 Instagram 對此受夠了。在經(jīng)歷了足夠的單頁應(yīng)用實(shí)踐后惕味,他們發(fā)布了一個叫做 React 的庫楼誓。React 不僅解決了這些缺點(diǎn),還改變了我們創(chuàng)建單頁應(yīng)用的思考方式名挥。
在下面的小節(jié)中疟羹,我們來看看 React 帶來的一些大事。
1. 自動化的 UI 狀態(tài)管理
在單頁應(yīng)用中禀倔,跟蹤 UI 并維護(hù)狀態(tài)是很難榄融,而且很耗時(shí)間。而在 React 中救湖,你只需要關(guān)注一件事情:UI 所處的最終狀態(tài)愧杯。它不關(guān)心 UI 開始是什么狀態(tài),也不關(guān)心用戶改變 UI 會采取哪些步驟鞋既,只需要要關(guān)心 UI 結(jié)束的狀態(tài):
React 負(fù)責(zé)管理一切力九。它搞清楚要發(fā)生什么耍铜,才能確保 UI 被正確表示。所以跌前,所有狀態(tài)管理的事情不再需要我們操心棕兼。
2. 快速的 DOM 操作
因?yàn)?DOM 操作是真的很慢,所以我們永遠(yuǎn)不會直接用 React 修改 DOM抵乓,而是修改內(nèi)存中的虛擬 DOM:
操作虛擬 DOM 非嘲橹浚快,當(dāng)時(shí)機(jī)合適時(shí)灾炭,React 負(fù)責(zé)更新真實(shí)的 DOM茎芋。它通過比較虛擬 DOM 和真實(shí) DOM 之間的差別,查明哪個改變很重要咆贬,然后在一個稱為 Reconciliation 的過程中作出最少量的 DOM 改變败徊,以確保一切保持最新。
注:簡單說掏缎, React在每次需要渲染時(shí)皱蹦,會先比較當(dāng)前DOM內(nèi)容和待渲染內(nèi)容的差異,然后再決定如何最優(yōu)地更新DOM眷蜈。這個過程被稱為
reconciliation
沪哺。
3. 用來創(chuàng)建真正可組合 UI 的 API
React 鼓勵我們將視覺元素分為更小的組件,而不是一整大塊:
編程領(lǐng)域中酌儒,模塊化辜妓、簡潔、自包含是好的理念忌怎。React 把這些理念帶到用戶界面中籍滴。很多 React 的核心 API 圍繞著更容易創(chuàng)建更小的界面組件,這些界面組件隨后可以與其它界面組件組合榴啸,創(chuàng)建更大更復(fù)雜的界面組件孽惰,就像俄羅斯套娃一樣:
這是 React 簡化創(chuàng)建 Web 應(yīng)用界面的主要方式。
4. 完全在 JavaScript 中定義 UI
這聽起來有點(diǎn)不可理喻鸥印。我們知道勋功,在 Web 標(biāo)準(zhǔn)年代,崇尚的是結(jié)構(gòu)库说、表現(xiàn)形式和行為分離狂鞋,也就是 UI 的結(jié)構(gòu)、表現(xiàn)形式和行為部分分別分離到 HTML潜的、CSS 和 JavaScript 三個文件中骚揍。完全在 JavaScript 中定義 UI,豈不是跟 Web 標(biāo)準(zhǔn)背道而馳么啰挪?
但是聽我說完疏咐。如果像過去一樣采用 HTML 模板的方式定義 UI纤掸,除了古怪的語法外,還有另一個主要問題浑塞。在模板中,除了只是顯示數(shù)據(jù)政己,我們被限制做很多事情酌壕。例如,如果你想根據(jù)特定條件歇由,選擇顯示哪一塊 UI卵牍,就不得不在應(yīng)用中到處寫 JavaScript,或者用一些古怪的框架特有的模板語法沦泌,才能讓它起作用糊昙。
例如,如下是 EmberJS 模板中的條件語句:
{{#if person}}
Welcome back, <b>{{person.firstName}} {{person.lastName}}</b>!
{{else}}
Please log in.
{{/if}}
而 React 實(shí)現(xiàn)的方式就很優(yōu)雅谢谦。UI 完全在 JavaScript 中定義释牺,我們可以利用 JavaScript 提供的強(qiáng)大功能在模板內(nèi)做各種事情。我們受到的限制只是 JavaScript 支持不支持回挽,而不是模板框架的限制∶涣現(xiàn)在,當(dāng)我們思考完全用 JavaScript 定義 UI 時(shí)千劈,可能會想到有些可怕的事情祭刚,比如引號、轉(zhuǎn)義符墙牌、大量 createElement 調(diào)用等涡驮。不要擔(dān)心。React 允許我們(可選)用 類似 HTML 的語法喜滨,即 JSX 來定義 UI捉捅,而 JSX 是 JavaScript 完全支持的。我們可以像下面這樣用 JSX 指定標(biāo)記鸿市,而不是編寫代碼定義 UI:
ReactDOM.render(
<div>
<h1>Batman</h1>
<h1>Iron Man</h1>
<h1>Nicolas Cage</h1>
<h1>Mega Man</h1>
</div>,
destination
);
所有這些允許我們使用很熟悉的 HTML 語法定義 UI锯梁,同時(shí)依然擁有 JavaScript 的強(qiáng)大功能和靈活性。更佳的是焰情,在 React 中陌凳,界面和 JavaScript 通常在一個地方。我們不再需要在定義一個界面組件的外觀和行為的多個文件之間跳轉(zhuǎn)了内舟。
5. 只是 MVC 架構(gòu)中的 V
React 并非一個完整的框架合敦,它主要是在視圖層,所有它關(guān)心的問題圍繞著界面元素验游,并且讓界面元素保持最新充岛。這意味著不管項(xiàng)目中所用的 MVC 架構(gòu)中的 M 和 C 部分是什么保檐,我們都可以自由用 React 作為 V 部分。這種靈活性讓我們可以挑選熟悉的技術(shù)崔梗,并且讓 React 不僅可以用來新創(chuàng)建 Web 應(yīng)用夜只,還可以用它來修改已有的應(yīng)用,而不需要刪除或者重構(gòu)整個代碼蒜魄。
總結(jié)
作為一個新的 Web 框架和庫扔亥,React 是相當(dāng)成功。它不僅解決了開發(fā)者在創(chuàng)建單頁應(yīng)用程序時(shí)面臨的常見問題谈为,而且還加入了一些額外的技巧旅挤,讓創(chuàng)建單頁應(yīng)用的界面變得相當(dāng)相當(dāng)簡單。因?yàn)樗菑?2013 年開始出現(xiàn)伞鲫,所以 React 在很多流行網(wǎng)站和 app 中得到應(yīng)用粘茄。除了 Facebook 和 Instagram 外,還包括 BBC秕脓、可汗學(xué)院柒瓣、PayPal、Reddit撒会、紐約時(shí)報(bào)嘹朗、Yahoo 等等。
本文介紹 React 可以做什么以及為什么它可以這樣做诵肛。在后面的教程中屹培,我們將深入講解本文中看到的所有東西,并且會涵蓋可以幫助我們在項(xiàng)目中使用 React 的技術(shù)細(xì)節(jié)怔檩。