爲何選用 React 建立混合型移動應用?

【編者按】本文做者爲 14islands 聯合創始人、創新 Web 開發者 David Lindkvist,主要介紹有關混合型應用搭建的方方面面。文章系國內 ITOM 管理平臺 OneAPM 編譯呈現。css

最近,咱們有幸與 Fjord 合做,從零開始爲其用戶打造了一款 HMTL5 混合型應用。html

混合型移動應用(Hybrid apps)能夠藉助多種 web 技術搭建應用,並將其打包爲原生應用(Native apps)以適應於多種移動平臺。前端

在本文中,咱們將分析使用 ReactCordova 建立 iOS 與 Android 應用時採用的技術以及面臨的挑戰。react

注意:React Native 在2015年首發。然而,在本項目開始時,React Native Android 版還未發佈,所以咱們沒法使用之。git

混合型應用中的挑戰

混合式移動應用已經不是什麼新鮮事了。同時,它固然也不是編寫全部應用的萬能鑰匙。真正的挑戰在於,達到原始應用的極致體驗,兼具流暢的動畫效果與時尚的用戶界面。github

過去,使用諸如 Backbone.js 這類更爲傳統的 JavaScript MVC 框架,咱們已經在這一方向上作了屢次冒險嘗試與努力。web

大多數混合式應用項目一開始,都具有快速、響應及時的用戶界面。以後,卻很容易撞上南牆。這一般出如今項目後期,此時,通過數週的努力,項目已經添加了許多的功能,DOM 中的內容也越發豐富。chrome

此時,視圖組件間的關係變得很是難以追蹤,而事件監聽器的循環依賴會致使過多的 DOM 讀寫操做。apache

進入 React

React 是一個用於建立用戶界面的 JavaScript 函數庫,一般被表述爲 MVC 中的 V(View,視圖)。redux

React 知道根據組件的狀態進行從新渲染,而且保存一個虛擬 DOM 以實現高效的從新渲染。這種方法很是棒,由於咱們寫代碼時就好像在從新渲染整個模板,而實際上 React 只會更新發生過改動的 DOM。

JSX

React 與常見框架的最大差異在於,JavaScript 邏輯與 Markup(標記)模板使用 JSX 語法寫在同一個文件中。

class MyTitle extends Component {
  render() {    return (
      <header>
        <h1>Hello World</h1>
      </header>
    )
  }
}

適應這種變化須要一點時間。可是一旦掌握,就能極大地你的提升生產力。

Mixins 對決 Composition

筆者是現代 JavaScript 的狂熱粉絲,偏好使用 Babel 編寫 ES2015 語法。

Mixins 不能與 ES2015 並用,緣由在此。因此,咱們選擇 Higher-order-components(高階組件)來建立功能特徵,而非 mixins:

/**
 * Exports a higher order component wrapping the component to decorate
 * @param ComponentToDecorate the component which will be decorated
 */
 export const withDecoratedData = ComponentToDecorate =>  
 class extends Component {
    constructor() {      
      this.state = { data: null };
    }
    componentDidMount() {      
      this.setState({ data: 'Decorated hello!' });
    }
    render() {      
      return <ComponentToDecorate {...this.props}  data={this.state.data} />;
    }
  }

以後,可使用 ES2016 裝飾器(Decorator)來應用組件。咱們能夠在 Babel 中選擇啓用 ES2016 裝飾器。

import {withDecoratedData} from '...';
// Decorate component using ES7 decorator '@'
@withDecoratedData
class MyComponent extends Component {
  render() {    
    return <div>{this.data}</div>;
  }
}

經過這種方式,咱們將視圖組件(View components)與咱們的數據存儲(Data stores)進行了聯結。

單向數據流

對於一個應用而言,視圖層只是表面——表面背後的部分纔是錯綜複雜的境地。React 能夠與大多數其餘框架結合使用,實現對現有數據模型的渲染。然而,大規模 MVC 應用與循環依賴的問題仍舊存在,所以,Facebook 推出了具有「單向數據流」的 Flux 設計模型,以使數據流動更容易預見。

爲何選用 React 建立混合型移動應用?

Flux 的實現方式不勝枚舉。在研究了其中一部分案例以後,咱們選定了Alt

UI 樣式與動畫

爲了讓應用盡量地接近原生,UI 動畫達到 60 幀每秒,而且沒有閃爍現象是相當重要的。移動端瀏覽器的 JavaScript 性能一直都慢得引人注目,所以,咱們確保只使用純 CSS 動畫與轉換。

行內樣式 對戰 CSS

最近,React 世界很是熱烈的一個話題是:是否使用行內樣式,也即:在元素樣式屬性內部設置樣式,而不使用 CSS。

實話實說,筆者更喜好 CSS,對行內樣式並不很是感冒。CSS 對重要內容的劃分很是清晰,而做爲 web 開發者,咱們早已熟知如何有效地應用響應式 Web 設計原則(Responsive Web Design principles)來支持不一樣的設備性能與屏幕大小。

行內樣式的最大爭議在於:「狀態」在很大程度上是 JavaScript 關心的問題。不少時候,咱們須要根據動態狀況來改變樣式。不過,你想一下就會發現,經過添加或刪除修飾符類以傳播狀態變更實際上是很完美的方法。

BEM 鍾愛 React

筆者偏好使用 Saas 與通過些微修正的 BEM 類命名慣例編寫大部分樣式。咱們修改了 BEM 塊名使其匹配 CamelCased JavaScript 類名,從而爲每一個組件實現明確的 JavaScript 與 CSS 組合。

class MyComponent {
  render() {
    const activeClass = this.props.active ? 'MyComponent--active' : '';    
    return (
      <div className={"MyComponent " + activeClass}>
        <h1 className="MyComponent__title">
          My title
        </h1>
      </div>
    );
  }
);

對於具有許多狀態修飾符的組件而言,這會顯得有些凌亂與繁瑣。爲此,筆者建立了本身的 bem-helper 以簡化 BEM 類名在 JSX 中的使用。

import BEM from 'bem-helper-js';
class MyComponent {
  render() {    
    return (
      <div className={BEM(this).is('active', this.props.active)}>
        <h1 className={BEM(this).el('title')}>
          My title
        </h1>
      </div>
    );
  }
);

它會自動從 JavaScript 類名中獲取塊名,並認爲 this.props.active is truetrue 時,下面的類名就會被渲染:

<div class="MyComponent MyComponent--active">  
  <h1 class="MyComponent__title">My title</h1>
 </div>

經過 React 實現動畫

對習慣了手動添加類或修改樣式的人而言,這部分可能會有點水土不服。現實是,咱們不得不後退一步,讓 React 處理 DOM 的全部更新。

大多數動畫庫都會直接訪問 DOM,所以,請仔細選擇。

幸運的是,React 團隊已經爲咱們提供了 ReactCSSTransitionGroup,能幫解決應用動畫類、在 DOM 中增減動畫元素等常見場景。在咱們的應用中,它有效地處理了頁面轉換。

收尾

咱們使用了 Apache Cordova來打包應用,生成 iOS 與 Android 版本。其設置至關簡單直白,而且提供了許多有用的插件,經過一個 JavaScript API 就能實現一些原生功能。

舉個例子,咱們包含了 Statusbar 插件,在運行時改變原生狀態欄的顏色。

爲何選用 React 建立混合型移動應用?

從 iOS 8 開始,咱們終於能夠在慣性滾動階段(也即在觸摸中止後持續的滾動動做)設置滾動事件。舊版 UIWebView 並不支持該功能,而 Cordova 默認使用舊版 UIWebView。

對於 iOS 9 用戶期待的 WKWebView 引擎,官方提供了一個 cordova 插件。然而,若是不啓用 CORS,沒法經過 file:// 協議使用 XHR。

總結

對於使用 React 完成此項目,咱們對本身的選擇感到欣慰。可是,咱們仍有一些值得注意的地方,以便在下次作出調整。

優點

  • 渲染性能的提高 —— React 能高效地實現 DOM 的更新
  • 簡化可重用組件的編寫
  • 強大的 JSX 語法,實現數據與標記模板的結合
  • 一旦體系決策達成,組件開始重用,生產力就能提升
  • 避免開發者直接接觸 DOM (也即:減小傷害性能的風險)

缺點

  • 若是不人爲直接修改 DOM,使用 React State 很難實現時間線複雜的動畫
  • 並不是全面的解決方案 ——缺乏經驗的開發者很難入門。須要選擇一個 Router, Flux 庫或數據層等等
  • 新的 React 版本發佈較爲頻繁,生態系統不夠成熟 ——大多數插件的變化比 React 還頻繁,並且 API
    一直在變化。在本項目中,咱們在 react-routerAlt 中都遇到過斷層式的 API 變化。Alt
    的變化尤爲迅速,相關文檔也不是最新的。在下一個 React 項目中,咱們會專一於 Redux

接下來去哪兒

如今,React Native 的勢頭愈來愈猛,所以值得進一步追蹤。關鍵的不一樣在於,它在 JavaScript 與原生 SDK 之間有一個代理層。它在單獨的線程中運行 JavaScript 代碼,所以在執行其餘操做時還能保證流暢的動畫。此外,經過 Flexbox 方法,React Native 也選擇了行內樣式而非 CSS。據估計,iOS 與 Android 之間超過 85% 的代碼庫能夠實現共享

本文系 OneAPM 工程師編譯呈現。OneAPM Browser Insight 是一個基於真實用戶的 Web 前端性能監控平臺,可以幫你們定位網站性能瓶頸,網站加速效果可視化;支持瀏覽器、微信、App 瀏覽 HTML 和 HTML5 頁面。想閱讀更多技術文章,請訪問 OneAPM 官方技術博客

本文轉自 OneAPM 官方博客

原文地址:http://14islands.com/blog/2016/03/03/why-we-chose-react-for-hybrid-app/

相關文章
相關標籤/搜索