为何选用 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/

相关文章
相关标签/搜索