為什麼我從 Angular 轉向 React

oschina發表於2017-02-09

  在過去的一段日子裡我大量地使用了 Angular 1.x,直到我開始使用 React。這兩個專案我使用得比較廣泛。但是,其中有幾個原因使我轉向了 React。剛開始原因還不是那麼清晰,但現在回顧起來,我認為我可以對此作出一個很好的總結了。

  為什麼我從 Angular 遷移到 React?我給出了 10 個理由。過去我喜歡 Angular 的各個方面,但是該是時候移除它了。這篇文章幫助人們理解 React 的優點, 也會讓人們瞭解 Angular 的優點,之後,再讓人們在 Angular 或 React 間作出選擇,或甚至是在 React 與 Angular 2 間作出選擇。

  本文並不打算批判 Angular。 長期以來,對我來說 Angular 具有很優秀的單頁應用程式體驗。 我喜歡這個框架,因為它給你所需要的一切。 由於我只是廣泛使用過 Angular 1.x,所以本文不打算談論 Angular 2,但我認為大多數的框架背後的原理仍然是相同的,本文所述同樣適用於 Angular 2。最後,在此我僅關於這兩種解決方案提供我的個人經驗。

  文章不是對兩種解決方案進行比較,而是關於為什麼考慮使用 React 作為解決方案的反思。 比較蘋果和橘子是毫無意義的。 但是,反思你為什麼可以使用或你為什麼選擇了一個特定的工具卻是有意義的。  

  接下來讓我們來看看我現在喜歡使用 React 的 10 個原因。

 React 僅是一個檢視庫

  單頁應用程式(SPA)遵循基於元件的使用者介面的常識。元件獲取輸入並返回元件的例項作為輸出。例如,輸出可以是簡單的按鈕元素。你只需要為你的元件定義一次輸入輸出和內部行為,然後就能在任何 DOM 層次中隨意地使用它來建立例項了。在最佳情況下,定義的元件易於重用並容易組裝到其他元件中。  

  React 是基於元件的使用者介面的理想選擇。它只是一個檢視庫,並解決了所有已描述的元件的要求。它是一個致力於僅解決一個問題的庫:提供了所有用於構建一個基於元件的使用者介面的工具。

  你可以看到 React 是作為 SPA 的一個組成部分。一旦你需要解決其他問題,你需要其他構建塊。您的應用程式需要路由?可以看看適合 React 的路由解決方案。您的應用程式需要可擴充套件狀態管理?可以看看不同狀態管理器的解決方案。您需要執行非同步請求嗎?可以看看像 fetchaxios 或 superagent 的解決方案。

  不過只用 React 也可以構建應用程式。它可能沒有應用程式所需的成熟的路由和複雜的狀態管理,但是它用於小應用程式沒有問題。在 React 學習之路通過構建這樣的應用程式來介紹了 React。

  React 本身只是應用程式的一個構建塊,它提供了基於元件的使用者介面解決方案。像其它的構建塊一樣,它是可替換的。基於使用者介面,你可以使用另一個解決方案來構建元件,它仍然可以和與其它構建塊結合。

  從這一點來看 Angular 是不同的。它不是一個庫,而是一個框架。它提供了不止一個構建塊。它是更剛性的解決方案。ReactJs 生態系統及其所有構建塊放在一起也可以看作是一個框架。但是與 AngularJs 相比,React 的構建塊是可替換的。而 Angular 幫你做好每件事。這看起來有些矛盾,一方面它應該很容易學,因為是使用自己的構建塊,但另一方面,同時學習每一個構建塊卻相當困難。在 React 中想一次學很多東西也不容易。

 React 是一個創新的地方

  React 只是生態系統的核心,它周圍所有的東西都是由構建塊組成。你可以靈活地選擇構建塊去解決不同的問題。但是 React 依然保持著他們之間簡單交換風格。他們之間簡單的交換風格,讓各種新奇的方法得以萌生。你可以使用 Redux 和 MobX 作為狀態管理的示例。Redux 在早期就已經擁有了很強勁的勢頭,那時,MobX 還是一個小小社群的倡導者,他可以讓那兩種解決方案相互交換。

  即使互動是 React 的核心建築塊。最近,像 Inferno 和 Preact 這樣的庫也開始和 React 競爭,他們可以用來代替 React。在 Augular 中使用這些方法是沒有任何意義的,因為 Augular 有它自己的解決方式。

  在 React 中可交換構建塊,這使得嘗試新方法成為可能。它的每個方法都給社群留了適應的空間,這使得 React 生態系統不斷創新。

 JSX - 混合了 HTML 和 JavaScript

  React 有一套稱為 JSX 的語法,用來製作元件。JSX 混合了 HTML 和 JavaScript。此外人們經常會在元素中使用內聯樣式,即混入 CSS。一開始可能讓人覺得混淆,但終歸會適應。你可以使用 JavaScript 組合和操作 DOM,但是它嵌入在 HTML 中。你可以使用內建的 JavaScript 功能,比如 map 和 filter 來顯示多個(過濾後的)DOM 節點。你還可以使用三元操作來按條件進行渲染。你可以在 HTML 中使用完整的 JavaScript 功能。

  在 SPA 解決方案中,它是一個新奇的方法,通過混合 HTML 和 JavaScript 來定義元件。其實這種方法在很早的服務端渲染方案(比如 JSP)中就已經存在了。

  與之相反,Angular 清楚地區分了邏輯和檢視的概念。它可以在 HTML 中使用內建的表示式,像 ng-repeat(Angular 1.x)或 ngFor(Angular 2)。這在 JSX 中會使用原生 JavaScript 的 map() 來完成。

 React 的 API 很簡單

  React 是一個檢視庫。它只解決一個問題並把這個問題處理好。因此需要學習和理解的方法會很少。

  React 元件使用生命週期方法。在 React 的 ES6 類元件中,你可以使用生命週期方法進入到元件生命週期。通常只需要寫 render() 這個生命週期方法,它把元素作為元件的新例項來進行渲染。渲染的程式碼塊會在元件初始化和每次元件更新時執行。這就夠了。不過你可以使用多個生命週期方法來新增高階的元件行為。比如,你可以使用 constructor() 來初始化有狀態的元件並新增類方法來操作狀態。每次狀態發生改變生命週期方法都會再次執行以更新檢視。

  元件的生命週期方法一共只有 9 個。多數情況下,你只會用到其中一半 - 哪怕是在成熟的 React 應用程式中。

  然後你還需要知道兩個 React ES6 類元件的方法:setState() 和 forceUpdate()。你一般不會用到後一個方法,它用於通過程式設計來強制更新一個元件。不過 setState() 通常用於更新元件的內部狀態,這些狀態是在 constructor() 生命期函式中初始化的。想像一下,你的列表元件中有一系列的項。然後你想從列表中新增或刪除元素。你可以使用把列表儲存在元件的內部狀態 this.state 中,再通過 setState() 更新列表。

  在 React 的官方文件 中你可以深入產瞭解 React 元件 API。

  現在你已經知道了所有基本的元件方法。React 中還有其它一些概念,比如 props 和 state、children 屬性或不同的元件申明。你可以慢慢來,一步一步地學完它們。

  總之 React 本身沒有陡峭的學習曲線。它只是一個需要掌握少量方法的檢視層。如果你首先學習的 React,我建議只學習 React,不要再學其它的。《React 學習之路》就是這種學習思想,它涵蓋了所有上面提到的你需要學習並掌握 React 的主題。

 輕量級元件 => 最佳實踐

  React 中的元件有兩個定義方式:ES6 類元件和函式形式的無狀態元件。後者只是一些函式,接收引數輸入並返回輸出一個元素——這也是元件,但是它們不需要模板,只需要定義普通的 JavaScript 函式。我不能說 Angular 定義元件更容易。

function Button({ onClick, children }) {
    return (
        <button onClick={onClick} type="button">
            {children}
        </button>
    );
}

  隨處使用函式式的無狀態元件是個非常好的實踐,但只在不需要元件狀態和生命週期方法的時候才能這樣做。這個最佳實踐使你可以定義輕量級的小元件,卻不失重用性、元件化和功能性,並且不會帶來副作用。這樣的最佳實踐已經體現在上面的樣板程式碼中。

 單向資料流

  與 Angular 1.x 不同,React 沒有雙向資料繫結。Angular 元件中的狀態管理最終變得混亂不堪。狀態幾乎不能預測,也沒有比較好的做法來處理它。在 Angular 1.x 中消除迴圈更新是件困難的事情。

  React 使用單向資料流規則。元件使用 setState() 來顯式更新內部狀態。它必須從元件的狀態物件 (this.state) 中獲取狀態,然後元件按更新後的狀態再次渲染。對於元件的輸入 (props),也會發生同樣的事情,如果輸入更新了,元件會通過其生命期方法 render 來更新。千萬不要直接修改輸入 (props) 或元件內部狀態 (state)。應該遵循單向資料流規則,使 React 的狀態管理更容易預測。

  此外,你還可以完全控制原生 HTML 元素。例如,HTML 中的 input 有其自己的狀態。你在 input 中輸入的文字可以通過 value 屬性獲得。在 React 中如果想完全控制 input 的狀態,以便在 input 的值發生改變時能通過 onChange() 回撥,呼叫 setState() 來更新元件內部狀態的值。之後可以在 input 中使用更新後的狀態值。這樣一來,元件內部狀態就是單一來源,值得信任。而 input 不再自己管理狀態。

<input
    value={this.state.value}
    onChange={(event) => this.setState({ value: event.target.value })}
    type="text"
 />

  單向資料流使得 React 的狀態管理可預測且易於維護。

 Redux

  Redux 並非 React 的必備元件。不過它們能完美適配,因為 Redux 只是一個構建塊,而 React 生態接受構建場。

  Redux 帶來可預測的狀態管理。自 2015 年 Dan Abramov 引入 Redux 以來,它就完全符合 flux 體系。Redux 是 flux 庫中的佼佼者,廣泛應用於各種場景。在 React 中使用 Redux 是很自然的事情。React 本身使用單向資料流,這與 Redux 相符。

  再來說 Angular 開發的那些日子裡,開發者們奮鬥在包含狀態管理的可伸縮的成熟應用中。在某些時候,你必須自己實現像 flux 那樣的東西,因為 flux 還沒成形。最後每個人都在羨慕 React 的開發者擁有無縫整合在生態系統中的 flux 模式。

  Redux 本身就是一個完整的生態系統。它是一個有著創新的構建塊,像 React 一樣。特別是在非同步領域,它支援不同的方式。比如,你可以選擇 JavaScript Promise、generator 或者可觀察物件。它是一塊試驗田,你可以在這裡找到自己做事的方法和創意。

 接近 JavaScript

  我必須說,從 Angular 轉向 React 的過程中我學習了不少 JavaScript 語言的概念。現在再回到 Angular,我很難回想起它的語法、用於 HTML 的表示式,或者申明。因為我沒有保留程式碼片段,所以回去使用 Angular 會花不少時間。我不知道事實是怎麼樣的,但是從 Angular 轉回 React 的時候,我認為那是不同的開發方式。React 非常接近 JavaScript,它只有一個構建塊。你一旦學會,就不是那麼容易忘記。

  React 非常接近 JavaScript。不僅 React,它的生態系統也與 JavaScript 類似。比如,Redux 的 action 和 reducer 本身就是 JavaScript。另外,整個 Redux 生態系統完全使用原生存在或即將實現的 JavaScript 功能,比如 generator 和可觀測物件。從庫的角度來看,它涵蓋的內容中沒有不是原生 JavaScript 的工具函式。

  另一個方面是 JavaScript ES6。也許 React 包含 ES6 只是一個巧合,因為 ES6 出現在同一時間。不過 React 一直在前進並吸收 ES6 的優點。採用 ES6 是件好事。還記得之前定義的無狀態的功能性按鈕元件嗎?如果使用 ES6 的箭頭函式,它看起來會有點不一樣:

const Button = ({ onClick, children }) =>
    <button onClick={onClick} type="button">
        {children}
    </button>

  在 React 及其生態系統中,你可以使用 ES6 簡潔優雅地進行表達,而且它還簡單並極具可讀性。使用它是自然而然的事情。

 函數語言程式設計

  函數語言程式設計自然地溶入了 React 及其生態系統。也許這是因為它與 JavaScript 極為接近。作為一個 React 開發者,應該儘量定義沒有副作用的函式 —— 純函式。這些函式能以可預測的方式組進行組合。首先,因為它們是純函式,相同的輸入一定會得到相同的輸出(可預測)。其次,你可以使用高階函式來組合它們(可組合)。

  可預見性和可組合性帶來的優勢同樣賦予了 React 的功能性元件,這就是為什麼 React 的元件是可預測和可元件(高階)的。

  程式設計方式正在發生變化。函數語言程式設計並不是新事物,但它是首次在 JavaScript 中採用。對於 JavaScript 生態環境中的函數語言程式設計來說,React 是這個思想的引領者之一。人的偉大之處就在於能向偉人學習,瞭解他們的優點和缺點並借他們的手來提高自己。React 和它的生態系統為你學習和使用函數語言程式設計提供了可能性。

 社群

  如果說下述大部分原因不適用於其它庫、框架和生態系統,那我是在撒謊。但我仍然認為值得提一下,React 環境背後的社群非常偉大。

  生態系統背後的人每天都在反覆不斷的嘗試。這可以追溯到 React 發明出來的時候,這關係到它的構建塊。新的解決方案有機會在社群中茁壯成長。構建塊會從開發者那獲益並不斷變化。

  React 背後的人們相互鼓勵。人們向社群貢獻創新、擴充套件庫或寫文章,怎麼都行。大家都會點贊激勵你繼續。當我開始寫關於 React 的文章時也受到了大家的鼓勵。

  人們不會在生態系統中駐足。如果出現問題,就一定會有解決辦法。有人會用庫來解決問題,或者在文章中解釋某個問題的最佳實踐。人們協助奮進。因為社群持續創新,所以總會有不少解決問題的新穎方案。

  正如我所說,我關於社群的想法是普遍的想法。我認為充斥著不同解決方案的社群都做的很好,它們相互鼓勵共同進步。這樣的環境下它怎麼會不變得偉大。

  總之,我說的這些是希望能幫助你更好的瞭解 React 生態系統。這也許會幫助你決定是否要在 2017 年跳上 React 這趟列車。對我個人來說,它幫助我進行了反思以決定開始學習 React。去年年中我們公司也在這個方面有一些小小的進步

  原文地址:https://www.robinwieruch.de/reasons-why-i-moved-from-angular-to-react/

相關文章