為什么選用 React 創建混合型移動應用?

AnalisaQke 8年前發布 | 42K 次閱讀 React ReactNative 移動開發

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

最近,我們有幸與 Fjord 合作,從零開始為其用戶打造了一款 HMTL5 混合型應用。

混合型移動應用(Hybrid apps)可以借助多種 web 技術搭建應用,并將其打包為原生應用(Native apps)以適應于多種移動平臺。

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

注意:React Native 在2015年首發。然而,在本項目開始時,React Native Android 版還未發布,因此我們無法使用之。

混合型應用中的挑戰

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

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

大多數混合式應用項目一開始,都具備快速、響應及時的用戶界面。之后,卻很容易撞上南墻。這通常出現在項目后期,此時,經過數周的努力,項目已經添加了許多的功能,DOM 中的內容也愈加豐富。

此時,視圖組件間的關系變得非常難以追蹤,而事件監聽器的循環依賴會導致過多的 DOM 讀寫操作。

進入 React

React 是一個用于創建用戶界面的 JavaScript 函數庫,通常被表述為 MVC 中的 V(View,視圖)。

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 應用與循環依賴的問題仍舊存在,因此,非死book 推出了具備“單向數據流”的 Flux 設計模型,以使數據流動更容易預見。

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 true 為 true 時,下面的類名就會被渲染:

<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 插件 ,在運行時改變原生狀態欄的顏色。

從 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-router 與 Alt 中都遇到過斷層式的 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 官方技術博客。

來自: http://blog.oneapm.com/apm-tech/689.html

 

 本文由用戶 AnalisaQke 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!