我是怎么從顧慮到熱愛ReactJS的(與AngularJS經典MVC數據綁定的對比)

jopen 9年前發布 | 48K 次閱讀 ReactJs
來自:http://ourjs.com/detail/5567c046d11a73aa4d000003

如果你問我兩個月前怎么看 React,我可能會說:

我的模板在哪?在我的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>
// Controller 
angular.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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!