別責怪框架:我使用 AngularJS 和 ReactJS 的經驗

zcfy發表於2016-10-02

  在過去的幾年裡,網站進化成了複雜的網頁應用。曾經的網際網路只涉及到簡單的商業資訊展現,而如今,看看 Facebook、Slack、Spotify 以及 Netflix,網際網路正在改變你的社交和生活方式。隨著網際網路的發展,前端開發這個行業達到了全新的高度,並得到了前所未有的重視。

  就像大多數前端開發者那樣,我們的技術棧曾經由 HTML 和 jQuery 構成。我們使用 AJAX 請求從後端獲取資料,使用 JavaScript 渲染新的 UI 元素然後將它插入到 DOM 中去,使用者互動通過事件繫結和回撥函式來實現。不要誤解我,我不反對上面那種方式,它們今天依然適合於大多數 Web 應用。

  然而,當一個應用的複雜度大幅度增加,一堆問題開始出現得比預期的更頻繁:你可能資料更新了,但漏掉了更新某一處展現,你通過 Ajax 獲取和更新了內容,但沒有繫結事件,還有另外一些問題,把這些全部列出來會是個很長的清單。這些問題讓你的程式碼逐漸變得不可維護,尤其是在多人協作團隊開發的專案中。這時候,你就需要使用前端框架來為你解決多人協作開發的種種問題了。

write_code

  1. React 福音

  當我們的團隊開始尋找一個合適的前端框架的時候,我們考慮了許多選擇,最後留下兩個選項 —— AngularReact

  Angular 是目前為止最成熟的方案:它擁有一個龐大的社群,你可以為大部分應用場景找到合適的第三方模組。

  React 也很有競爭力,它以 JavaScript 為中心的設計看起來很有前途,而且它效能很好。雖然它還是 Beta 版本,但是 “由Facebook團隊開發的” 這一點給它的競爭力加分。

  我們決定給 React 一個機會,選擇了使用它。

  最初使用 React 讓人感覺棒極了,我們可以用 JavaScript 來做一切:展現一段 HTML,通過遍歷陣列渲染一個列表,優雅地改變一個變數的值,然後看著它通過 props 傳播到各處,更新要更新的內容到可複用元件裡,然後一切就緒了,沒有一坨一坨的程式碼,只有真正的停下來思考。React 解決了我們在團隊開發中編寫可維護程式碼的訴求。

teamwork_1

  2. React + Flux = ♥

  但沿著這條路走下去,我們發現並不是一切都很美好。我們遇到的第一個大挑戰就曾讓我們考慮是否應該放棄 React —— 我們陷入了回撥迷宮。

  由於 React 的單向資料流性質,如果子元件需要更新父元件的狀態,父元件就要傳一個回撥函式給它。這咋看起來沒有什麼大不了的,然而如果你的元件要更新 root 元件的狀態,你就不得不將 “this.props.updateCallback” 沿著資料流一層一層傳遞下來。

  儘管如此,我們喜歡 React,繼續使用它完成我們的工作。通過努力,我們找到了 Flux,它是一種規範化單向資料流的架構思想。它由四個主要元素構成。

  • Store: 負責儲存資料和應用狀態。
  • Action: 觸發狀態改變。
  • Dispatcher: 管理 action 並將它們導向對應的 store。
  • View: 展現 store 中的資料,派發 action - 這塊是 React 中已有的。

  採用 Flux,我們就不用將狀態儲存在 root 元件中,然後將 update 回撥一層層傳遞給它的子元件。React 元件通過 store 直接獲得資料,通過呼叫 action 來改變狀態:這樣簡單、優雅,不會讓你抓狂。Flux 補充了可預測的行為和一些標準到被 React 框架約束的程式碼中。

  3. 狂野的 Angular 出場……

  ……它採用以 HTML 為中心的程式碼且並不超有效

pokemon_effective

  最近,我開始參與一個 Angular 專案。我加入的時候這個專案已經完成了很大一部分了,所以不得不用 Angular,沒有回頭路。作為一個忠實的 React 開發者,我吐槽 Angular。當我開始寫第一行 Angular 程式碼的時候,我就真心詛咒它。這就是所謂的:如果你愛 React,那你就恨 Angular

  我不能自欺欺人,在一開始,我寫 Angular 程式碼一點也不開心。將框架定義的屬性(或者,更恰當地說法是 directives)寫入到 HTML 中的做法讓我感覺很不爽。我得費很大勁才能實現很簡單的功能,比如改變 URL 的時候不重新載入 controller 或者渲染基礎模板。

  當我在表單中遇到一個由於 ngIf directive 建立一個新的子域而導致的問題時,我處理起來還是很費勁。還有當我想要從一個準備傳送給伺服器的 JSON 中移除一些空白欄位時,我發現 UI 中對應的資料也被一併移除了 —— 丫的雙向繫結 ╮(╯▽╰)╭。還有當我想要使用 ngShowngHide 來顯示一個 HTML 塊同時隱藏另一個 HTML 塊時,在一瞬間,兩者同時顯示了。我明白許多問題是我自己的問題,而我想要指出的是,Angular是不可預測的,使用它的時候會遇上各種各樣的坑。

struggle

  當然,Angular 還是善於處理很多事情的。內建的 HTTP 請求模組 非常棒,對 promise 的支援也很好。另一個我無法吐槽的好東西是:內建的表單控制器,它為 input 欄位提供了預設的格式化、解析和校驗,而且還提供了一個很好的外掛用來展示錯誤資訊。

  使用 Angular 也能讓開發團隊與頁面製作團隊協同工作變得更簡單。在我們團隊,有專門的頁面重構工程師負責寫 HTML 和 CSS,Angular 能讓我們的工作無縫對接:重構工程師負責 HTML 和一些額外的標籤,我負責處理邏輯。如果我們使用的是 React,那麼至少讓重構工程師寫元件會是一個挑戰,要麼得讓他學會寫基本的 JSX,要麼我就只能自己將他寫的 HTML 複製貼上到 JSX 中。

  還記得前面提到的 URL 替換和模板渲染問題嗎?其實沒關係,人們通常使用第三方的路由庫(ui-router)它們比標準的 (ngRoute)要好用。最後,Angular 也沒有我之前認為的那樣糟糕。之前的大多數抱怨要麼是因為我習慣了 React 思維,要麼是我還不夠專業。

obama_not_bad

  4. 總結: AngularJS 與 ReactJS

  React 使用原生 JavaScript 函式讓開發者可以建立一個有固定生命週期的、單向資料流的可複用元件。React 與 Flux 架構(或者受 Flux 啟發而產生的其他架構,比如 Redux)相結合,能讓團隊長期維護一個專案變得更加容易,使用它不用擔心解決一個 bug 會引入更多新 bug。但是,如果你的團隊有專門寫 HTML 和 CSS 的人,React 會帶來額外的學習成本,因為它改變了傳統的開發流程。而且 React 的效果還非常依賴你選擇的組成你的應用的模組。

  另一方面,Angular 專注於設計簡單的雙向資料繫結,當你改變 controller scope 中的內容,變化將會被自動地同步到UI(效果如同魔法般)。它自認為節省了配置的時間,開發者不用像傳統開發模式那樣考慮用各種設計模式組織程式碼然後從上百種可選的方案中選出一個核心模組。使用雙向繫結為開發帶來了便利,然而它也容易在長期維護的過程中由於修改部分程式碼而產生不可預期的 bug,尤其是那些在過去的幾個月中沒有再動過的程式碼。

  那麼,我從頭開始建立 app 的首選方案是什麼呢?

  從長遠而言,我個人傾向於選擇 React,使用 Redux 架構,使用 Axios 支援 promise-ready 的 HTTP 請求,以及使用 react-router 處理路由。不過,這也取決於團隊的經驗:如果有專門寫 HTML 和 CSS 的人,我肯定會選擇 Angular。兩個框架都各有利弊,從構建可維護專案的目的來考慮,最關鍵的還是如何讓小夥伴們寫出好程式碼。

At the end, Angular was not as bad as I expected.

相關文章