我是怎么從顧慮到熱愛ReactJS的(與AngularJS經典MVC數據綁定的對比)
我的模板在哪?在我的JavaScript里寫這么多HTML干什么?JSX看起來很怪!趕快把它從我的項目里面去掉!這是因為我還不了解它。現在我保證,React決定是正常的路徑,請聽我尾尾道來。
經典的MVC
在一個交互式應用程序中狀態的管理是一切罪惡的根源。“傳統”的方式是采用MVC架構,或者是一些變種。
MVC提出你的模型(Model)是檢驗真理的唯一來源 - 所有的狀態都在那里。視圖(View)源自模型,并且必須跟模型保持同步。當模型轉變時,視圖也要同步改變
最后,用戶通過控制器(Controller)控制交互,由它更新模型。到目前為止,這工作地很好。

當Model改變時重繪View
這看起來很簡單。首先,我們需要來詳細我們的View - 它是一個對DOM的映射。然后,每當用戶更新模型時重繪整個DOM,對吧?不幸的是,事情不是這么簡單,原因有二:
1. DOM 實現上是有狀態的, 像input文本的內容。如果你重繪整個DOM, 這部分內容就會丟失。
2. DOM 操作 (像移除插入的結點) 真的非常慢. 持續不斷地重繪會導致嚴重的性能問題。
所以,我們怎樣同步Model和View來避免上面的問題?
數據綁定 Data binding
在過去3年,框架級別的通用解決方案是采用數據綁定。
數據綁定是讓你的模型和視圖,擁有自動同步的能力。通常情況下,是將JavaScript對象和DOM進行同步。
它通過你的數據聲明的組件之間的依賴關系來實現。狀態的變化會在整個應用程序中傳播并通知所有依賴的對象,然后自動更新。
讓我們來看看它是如何工作的和一些著名的框架。
Knockout
Knockout主張MVVM模式,并幫助您實現“View”部分:
// View (一個模板)<p>First name: <input data-bind="value: firstName" /></p><p>Last name: <input data-bind="value: lastName" /></p><h2>Hello, <span data-bind="text: fullName"> </span>!</h2>// ViewModel (diplay data... and logic?)var ViewModel = function(first, last) {this.firstName = ko.observable(first);this.lastName = ko.observable(last);this.fullName = ko.pureComputed(function() {// Knockout 會自動偵聽依賴。它知道fullName會依賴firstName和lastName.return this.firstName() + " " + this.lastName();}, this);};
然后,萬事大吉了。改變任一輸入的值將觸發DOM的變化。你從來不用寫數據與視圖關連的邏輯代碼。效果不錯,是吧?
為什么模型是真理的唯一來源?這個ViewModel應該從哪里獲取狀態?它是如何知道Model的變化的?這是很有趣的問題。
Angular
Angular介紹了如果在Model和View之間同步數據。下圖來自其文檔:

但是......View應該與Model直接通信嗎?難道他們是緊耦合的?
無論如何,讓我們來看看Hello World示例:
// View (一個模板)<div ng-controller="HelloController as hello"><label>Name:</label><input type="text" ng-model="hello.firstName"><input type="text" ng-model="hello.lastName"><h1>Hello {{hello.fullName()}}!</h1></div>// Controllerangular.module('helloApp', []).controller('HelloController', function() {var hello = this;hello.fullName = function() {return hello.firstName + hello.lastName;};});
通過這個例子,Controller看起擁有自己的狀態,而且表現的像個Model或者一個ViewModel?假設Model是其它的什么東西,它是如何保持跟Controller的同步的呢?
data binding的問題
數據綁定在小的例子里工作地很好。然而,當你的app不斷地迭代時。你可能會碰到下面的問題。
聲明依賴會快速地引入循環
最常見的問題是在應對狀態變化時所產生的副作用。從Flux的這篇報道可以很清楚地了解依賴地獄的蠕變:

在這種情況下,你能預測當一個Model發生變化時會發生什么嗎?推理是非常非常困難的,因為它的執行次序可能是非常隨意的。
模板和顯示邏輯被人為地割裂
視圖的作用是什么?呈現的數據顯示給用戶。ViewModel是干什么的?呈現的數據顯示給用戶。有什么區別?沒有!
模板分離技術,我不關注? 皮特·亨特
最后,一個視圖組件應該能夠操縱它的數據,并能以所希望的格式呈現它。但是,所有的模板語言本質上是殘缺的:他們永遠不能達到同樣的表現力和效能的代碼。
非常簡單,{{# each}}, ng-repeat 和 databind="foreach" 都僅能替代天然的和瑣碎JavaScript中的一個for循環。不能再進一步。因為,沒有filter或map提供給你。
Data binding 是圍繞重新渲染的Hack手法
當狀態變化時,人們都希望重新渲染整個應用。通過這種方式,我們可以阻止一個萬惡問題:狀態是隨時間變化的。
了解非死book的React框架
事實證明,他們做到了。React實現了一個虛擬DOM(virtual DOM)來解決上面的問題。
virtual DOM到底是什么?
我們來看一看React的例子
var Hello = React.createClass({render: function() {return <div>Hello {this.props.name}</div>;}});React.render(<Hello name="World" />, document.getElementById('container'));
這就是一個React組件的所有代碼。你只需要有一個渲染方法。復雜嗎?
OK,<DIV>是什么?這不是JavaScript的寫法!確實JS里肯定沒有這個東西。
你的新朋友: JSX
這個碼被實際是用JSX寫的,一個Javascript的超集,其使用括號語法定義組件。上面的代碼,當編譯成JavaScript時,將變成:
var Hello = React.createClass({displayName: "Hello",render: function() {return React.createElement("div", null, "Hello ", this.props.name);}});React.render(React.createElement(Hello, {name: "World"}), document.getElementById('container'));
你有沒有注意到調用的createElement?這些對象組件的Virtual DOM實現。
很簡單:首先React在內存中組裝整個應用程序的結構,使用這些對象。然后,它把這個結構轉化為實際的DOM節點,將它們插入您瀏覽器的DOM中。
OK,但是為什么我們的HTML要變化那些奇怪的createElement函數呢?
Virtual DOM 非常快
正如我們已經討論的,操縱DOM貴的離譜,所以這個操作做得越少越好。
React的Virtual DOM,使得這個操作變得很快。通過這種方式,React能夠比較兩種DOM樹的差異,然后計算出能使DOM新化所需的最小變化。這意味著兩件事情:
如果輸入文本重新呈現和陣營期望它有該內容,它不會觸及輸入。沒有更多的虧損狀態!
如果React重新渲染Text的內容。它不會動input。不會有狀態丟失。
比較的Virtual DOM的性能還可以,當它會在準備改變DOM前進行充分的比較,它只會執行盡可能少的操作。因此渲染是很快的!
React印射狀態到DOM中
Virtual DOM在渲染進行進行比較的是React魔法的一部分。并且它能從根本上使我們能夠有一個更簡單的框架。多么簡單?
這是一個React組件應該有的功能,它能將應用程序的狀態映射到DOM中。你能發揮JavaScript的全部能力來描述你的UI - 循環,函數,Scope,組件,模塊 - 它不是一個殘缺的模板語言。
var CommentList = React.createClass({render: function() {var commentNodes = this.props.data.map(function (comment) {return (<Comment author={comment.author}>{comment.text}</Comment>);});return (<div className="commentList">{commentNodes}</div>);}});var CommentBox = React.createClass({render: function() {return (<div className="commentBox"><h1>Comments</h1><CommentList data={this.props.data} /></div>);}});React.render(<CommentBox data={data} />,document.getElementById('content'));
開始用React
第一次用React可能有點另人生畏。它提出了一個非常大的風格轉變,這其實不是很舒服。然而,當你開始用時,你會發現優勢明顯。
快樂編碼!
原文地址: firstdoit.com
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!