原文連接 : Getting to Grips with React (as an Angular developer)
原文做者 : DAVE CEDDIA
譯者 : 李林璞(web前端領域)
譯者注:翻譯若有疏漏,歡迎指出!感謝!轉載請保留此頭部。html
你是一個對 React 感興趣的 Angular 開發者嗎?不用擔憂,這真的不會讓你成爲一個背叛者或其餘什麼,真的。前端
或許你早就已經開始玩 React 了:閱讀了 Facebook 的官方教程,建立了一些組件...react
也或許你正處於我幾個月前處於的境地:對React徹底沒有經驗,除了據說過它有多快,它有個虛擬 DOM 的概念,單向綁定,和一些像 Flux , Redux 和 Reflux 之類亂七八糟的東西。git
在接下來一系列的文章裏我將嘗試幫助你將你辛苦習來的 「Angular」 主義知識應用到 React 當中。github
在 Angular 裏,你可能已經習慣去編寫各類指令 directive
。若是你是按照流行的規範去編碼的話,相信你程序的各個部分都是由一個或多個指令構建而成,並處處都使用了隔離的做用域 scope
(若是這聽起來很熟悉但並不像你所作的話,或許你能夠閱讀一下將scope轉化爲controllerAs)。web
React 有着相同的概念:編寫組件 component
。將你的程序按功能拆分紅組件塊,並儘量讓每一個組件塊保持獨立和可複用性。事實上,這個想法並非 React 或 Angular 首創的 - 它只是一種很棒的軟件開發實踐方式。儘量寫一些簡短並具有可複用性的代碼(函數,組件,指令,隨便你怎麼稱呼它們)。app
一個關鍵的差異在於 React 裏 全部東西都是組件 ,從根節點到下面全部。Angular 讓你使用 ng-controller
去混合和匹配全部指令,並在以後特定地路由出各自的指令和模板... React 讓這個事情變簡單了一點。全部東西都是組件,頁面,按鈕甚至是路由,咱們隨後會講到這些。less
好了,因此說 React 的「組件」是相似於「指令」的。那麼它的代碼看起來是怎樣的呢?函數
下面是一個展現歌曲名字的 Angular 指令:工具
angular.module('demo', []).directive('songName', function() { return { scope: { song: '=' }, restrict: 'E', template: '<span class="song-name">{{ ctrl.song.name }}</span>', controller: function() {}, controllerAs: 'ctrl', bindToController: true }; });
接下來是用 React 寫的相同功能的組件:
var SongName = React.createClass({ propTypes: { song: React.PropTypes.object.isRequired }, render: function() { return <span className='song-name'>{this.props.song.name}</span>; } });
你立刻就能夠發現一些類似之處:它們都指望獲得一個 song
對象,並都彷佛有各類各樣的模板。
一些不一樣之處在於:React 相對 Angular 有着更少的代碼。我敢說...更簡潔了不是嗎?React 裏,指望的參數(song
)有着某種類型驗證,而且 HTML 沒有引號!
事實上那個看上去沒加引號的 HTML 並非真正的 HTML。(等下就會講到)
React.createClass
和 angular.directive
相似 - 它建立了一個組件類。這個組件 必須 有一個 render
方法,propTypes
是一個可選對象,但最好把它寫上。
仍是要對得起 Angular ,它的1.5版本其實介紹了一個 component
方法來縮短指令的長度,因此上面的指令能夠簡寫成下面這樣:
angular.module('demo', []).component('songName', { bindings: { song: '=' }, template: '<span class="song-name">{{ $ctrl.song.name }}</span>' });
更簡單的寫法。它甚至默認沒有控制器!我推薦閱讀一下Todd Motto的關於組件方法的文章並在你的代碼裏嘗試一下。
但它仍是沒有 propTypes
...
propTypes
是一個驗證組件所需參數的方法。你能夠把個別參數標記爲「必需的」或「可選的」(默認它們都是可選的),把它想象成類型檢測吧。
下面是真正很酷的部分:若是你指定了propTypes
並說明一個參數是必需的(像上面那樣),而後你忘記把它傳進來,你就會在控制檯獲得一個提示信息。
比起 Angular 這真的太棒了!當你忘記給指令傳參時你就不再怕莫名其妙地報錯了。
什麼是 "prop" ?它其實是 「property」 的簡寫(感謝 React 的開發者,讓咱們不再用打出 this.properties
或者 this.propertyTypes
了)。
你能夠把 props
看做是傳給組件的屬性。就像在指令裏,你會在 HTML 元素裏傳遞屬性同樣 - props
會在 JSX 元素裏被看成屬性傳遞。
下面是 Angular 裏指令的使用方法:
// Notice how you have to mentally translate 'songName' to 'song-name'? <song-name song="ctrl.song"></song-name>
而後下面是 React 裏組件的使用方法:
// Notice how you DON'T need to mentally translate SongName to anything? <SongName song={theSong}/>
全部沒有子元素的標籤在 JSX 裏均可以自終止。
但讓咱們先花幾分鐘來說講 JSX吧...
在我對 React 瞭解很少的時候,我知道它是把 HTML 和 JS 混合起來的,而後我就想這樣作真的很 醜陋 啊。我意思是,這對於最佳實踐的思考來講已經不少年不會這麼寫了不是嗎?從那段使用 jQuery 的黑暗日子開始,咱們就已經知道在 JS 裏寫 HTML 元素是一件很取巧並且開發體驗至關糟糕的事情,因此爲何 React 會再次犯一樣的錯誤呢?
因此,這裏有兩件事情須要搞清楚:
那並非字符串。
你注意到它是怎麼作到不給 「HTML」 加引號的嗎?那是由於它並非 HTML。不加引號也並非一種語法糖,React 是不會將那個東西轉換成 HTML 的。
那並非HTML。
那是 JSX 。我知道它長得很像 HTML ,立刻你可能會想:「JSX嘛 ...只是對 HTML 作了一些細微的改變而後換了個名字而已」,好吧,你也能夠那麼說。我倒以爲它是給咱們提供了一種用函數調用去建立 DOM 元素的語法糖。
建立 DOM 元素的函數調用?是的,看看下面的代碼:
// This JSX... <span className='song-name'>{this.props.song.name}</span> // Compiles to this function call: React.createElement('span', {className: 'song-name'}, this.props.song.name); // React.createElement('tagName', props, children);
看起來還挺有道理的,不是嗎? HTML 建立嵌套的 DOM 節點,那咱們就用嵌套的函數調用替代了嵌套的 DOM 節點...
// This is valid JSX: <div> <span className='greeting'> <strong>Hello</strong> <strong>World</strong> </span> </div> // ...which compiles to this call: React.createElement('div', null, React.createElement('span', {className: 'greeting'}, React.createElement('strong', null, 'Hello'), React.createElement('strong', null, 'World') ));
實現上來講,這些 React.createElement
方法並無建立真正的 DOM 節點,它們建立了虛擬的 DOM 節點。
因此說咱們並非把 HTML 字符串寫到 Javascript 裏的!
但代碼邏輯始終仍是和表現層混合起來的!那可不能算對!這麼多年的軟件開發實踐告訴咱們這樣作是很很差的。放心,如今只是還沒作完呢,你並無把視圖和邏輯混合起來。
我認爲這是一種相似「貨物崇拜」的東西,咱們常常在沒真正搞清楚爲何的狀況下去贊同和執行。有不少很好的理由去說明爲何須要把邏輯和視圖層給分離開,但當你回頭再看會發現一樣也有不少很好的理由去合併它們。
或許你已經寫過一些帶有控制器和分離的模板文件的 Angular 指令了是吧?
告訴我你有多麼常常在看不到或者沒法修改控制器的狀況下去到模板文件裏去修改一些東西?又有多麼常常在沒有接觸到模板的狀況下去修改控制器?
這些看上去算是你對關注點的分離嗎?
咱們喜歡把 JS 和 HTML 分離到不一樣的文件裏去讓它們「關注點分離」,可複用性咱們來了!
但其實它們不多會那樣工做。一個指令的控制器和模板一般會牢牢關聯在一塊兒,因此很天然地,它們就像是硬幣的兩面。把代碼分離到不一樣的文件裏並不會自動致使關注點分離。
若是你還沒注意到的話,其實我是想嘗試經過上面的說法告訴你模板和邏輯控制實際上是能夠共存在一個文件裏的,並且這樣作或許看起來更有道理一些。
我敢打賭你仍是充滿疑惑。正常,我曾經也是的。
我的來講,我發現從長期以來信服的理論當中跳出來到一個看似徹底相反的位置確實是一件至關困難的事情。我試過親自去嘗試那麼作並證實給本身看這個新方法並非那麼糟糕。
但願你也能夠去作一樣的事情,只須要一點點時間。去嘗試一下 React 的官方教程(不須要什麼亂七八糟的工具 - 下載並運行他們的服務就能夠開始寫代碼了),或者也能夠試一下個人三分鐘輸出 Hello World 教程(不須要編譯哦!)。
或許就能夠像我作的那樣,你會發現寫 React 組件確實頗有意思。又或者你會發現 React 並非你想要的東西,但至少你嘗試並驗證過了。
若是你決定使用它了,那就回來這兒吧,我等你!