zoukankan      html  css  js  c++  java
  • 慢牛系列三:React Native实践

    上次发布了我的慢牛股票APP之后,有园友反馈有点卡,这个APP是基于Sencha Touch + Cordova开发的,Sencha本身是一个比较重的框架,在Chrome里运行性能还是不错的,但是在Android的WebView里,性能受限于机器的配置,在我的小米2s里表现还行,在小米4s里开起来比较流畅,但是Android机型相比IOS太多样了,Sencha Touch在iOS里表现不错,不过我还没编译iOS版本。 

    后来我又试着用了下Ionic框架,基于AngularJs开发,这个框架要轻量,在慢牛股票的微信公众号里试着开发了几个页面,感觉很不错,本来想用AngularJs重新做一个APP,但是后来又接触了React Native,试着用了下,React Native的编程体验类似于Sencha Touch,完全的组件化,JSX的语法很有意思,逐步习惯以后,用起来也很顺手。

    有兴趣的朋友可以对比下这三个方案,我留下这个三个方案的下载地址:

    慢牛股票APP(Sencha Touch+ Cordova)方案

    慢牛微信公众号(Ionic方案)

    Demo(React Native方案) 

    截图动画:

     

    React Native相比上面两种,体验更顺畅,当然,原生的应用肯定是比在WebView里体验好的,ReactNative结合了原生开发和Web开发优势,不过,React Native现在对Android的支持不算太好,比如动画。

    ReactNative的Flex布局,组件化思想很不错,上手快,不过因为最终显示的是原生,所以还是要多了解下原生的开发,必要时自己做桥接,比如我在做K线图,苦于找不到相关的组件,只有自己桥接了MPAndroidChart。

    Demo主要实现了几个我认为比较关键功能:

    1、导航

    2、列表

    3、下拉刷新

    4、图表

    这几个功能点实现以后,后面的工作就轻松得多了,比如表单提交,第三方登录,设置等等页面。

    下面说下这几个点的实现方式,

    1、导航

    侧滑菜单

    熟悉原生开发的同学一看就知道,这是原生的DrawerLayout,通过RN桥接过来, 很滑,很顺,之前用CSS3在WebView里做过侧滑菜单,当然比不上这个啦!

    页面切换

    利用了RN的Navigator组件,这个组件实现了一个Stack,每次新开页面就是向Stack里Push新的UI导航信息,然后在Render时判断要显示哪个UI组件,这个导航组件会把历史UI移动可视范围之外,利用Opacity把UI设置为透明,然后绝对定位到可视范围之外,返回时,再把历史UI移动可视范围,这样,历史UI的状态还是保持的,这样的导航在Web上也是可以借鉴的。

    这个导航还可以设置转场动画,看源代码,确实是实现了不少的动画,包括PushFromRight,FloatFromRight,FadeAndroid等,但是设置后不起作用,只有FadeAndroid有效果,但是动画一闪而过,不顺滑,这里对Android的支持不太好,或者是我的哪里设置不对?

    Tab切换

    Tab切换做起来比较容易,不过有一点,在页面切换过程中,不要重新Render每个Tab对应的内容,重新Render会清除页面的当前的状态,比如滚动条的位置等,而且性能差,借鉴Navigator,把非焦点的Tab页面移动可视范围之外即可。

    Demo中按钮的图标都是矢量的,图标字体的优点不用说了,原生系统也可以用图标字体了,对不喜欢用图片的同学真是一个喜讯,一想到要做那么多图片,要考虑每种分辨率,就头脑哇,这里用了github上的一个开源组件react-native-icons。

     贴段代码:

      render: function() {
        var navigationView = (
          <SideMenu onItemSelected={this.onItemSelected}/>
        );
        return (
          <DrawerLayout
            ref="drawerMenu"
            drawerWidth={300}
            drawerPosition={DrawerLayout.positions.Left}
            renderNavigationView={() => navigationView}>  
              <Navigator
                ref='navigator'
                debugOverlay={false}
                style={styles.appContainer}
                configureScene={(route) =>Navigator.SceneConfigs.FloatFromRight}
                initialRoute={{name:'main',component:(<TabPanel/>)}}
                renderScene={(route, navigator) => {          
                    return (route.component);
                }}
              />
          </DrawerLayout>
    );
    

    2、列表:

    Demo里我实现了一个股票的列表,列表拆分成了List组件和ListItem组件,利用React开发,组件化思想很重要,这在之前用Sencha时也有这样的体验。

    列表这里没有用ListView组件,是用ScrollVIew包了一个ListTtem的列表,如果数据量比较大,或者比较复杂列表,可以用官方的ListView来做,性能会比较好,每次更新只会更新变化的列表项,也提供了分类,设置表头和表尾等等。

    贴段代码:

      createRows:function(){
        return  this.state.myStockList.map(function (obj) {
          return (<StockItem key={obj.code} id={obj.code} data={obj}></StockItem>);
        });
      }, 
      render: function() {
        return (
           <SwipeRefreshLayout 
              ref={(control)=>{this._view=control}} 
              style={styles.scrollView} 
              onRefresh={this.reloadData}>   
                <ScrollView style={{flex:1}}>
                  {this.createRows()}
                </ScrollView>
            </SwipeRefreshLayout>
        );
      }
    

      

    3、下拉刷新:

    在github上,有不少的下拉刷新组件,比如;react-native-gifted-listview但是都是iOS上可以下拉,在Android上有Bug,文档上这样解释:

    Pull-to-refresh in Android (tried to implement it but it seems that onResponderRelease event is not catchable yet in Android ListView - React-Native

    关于如何在RN里响应手势,我还没怎么了解,后面再动画方面多研究下,因为了解下原生控件的桥接,所有就偷懒了,把原生的SwipeRefreshLayout控件做了桥接,包裹上ScrollVIew,就可以实现下拉刷新了,在JS里响应SwipeRefreshLayout发送的刷新事件,同时开放一个关闭刷新的接口,JS端获取数据更新后,关闭刷新状态。

    4、图表

    图表这里,我花的时间最多,目前也不是很完善,只不过,可以显示K线了,但是在交互上还是要加强。

    之前在Web端做过两次K线图,一个是Sencha的,一个是D3的,用了RN以后,之前的图表都用不上了,也考虑过套个WebView,用D3来做,但是效果肯定不好哇,最后还是学习了原生开发,学习了原生UI的布局,组件的继承架构,学习使用MPAndroidChart组件,如何桥接原生组件等等,收获不小,现在开发一边打开Android Studio,一边打开Sublime。。。

    原生的组件,View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的,RN提供了两种ViewManager类用来桥接这两类组件,ViewManager管理组件的创建,布局,以及属性设置,事件触发。

    贴段代码:

    android端(桥接图表代码片段):

    public class MPBarLineChartManager extends SimpleViewManager<BarLineChartBase> {
        private String CLASS_NAME="MPBarChart";
       
        @Override
        public String getName() {
            return this.CLASS_NAME;
        }
    
        @Override
        protected BarLineChartBase createViewInstance(ThemedReactContext reactContext) {
            BarChart chart=new BarChart(reactContext);
            return  chart;
        }
    
        @ReactProp(name="touchEnabled",defaultBoolean = true)
        public void setTouchEnabled(BarLineChartBase chart,boolean enable){
            chart.setTouchEnabled(enable);
        }
       ...... }

    js端:

    var { requireNativeComponent,PropTypes } = require('react-native');
    
    var iface = {
      name: 'BarChart',
      propTypes: {
      	data:PropTypes.object,
      	touchEnabled:PropTypes.bool,
      	......
    	scaleX: PropTypes.number,
    	scaleY: PropTypes.number,
    	translateX: PropTypes.number,
    	translateY: PropTypes.number,
    	rotation: PropTypes.number,
      },
    };
    
    module.exports = requireNativeComponent('MPBarChart', iface);
    

      

    这个图表的桥接项目我发布到了github上,目前实现了对柱状图,线形图,以及组合图表的桥接。

    https://github.com/hongyin163/react-native-chart-android

    有希望用图表的同学可以利用下,要是能继续帮忙增强就更好啦!

    学会了桥接原生组件以后,我就陷入了一种模式,只要在RN里实现有难度的,我就想桥接一个原生的Android组件,虽然知道这样不太好,因为如果用了太多原生的组件,后续的迁移麻烦了,当然最好利用官方提供的Android和IOS都支持的组件,最好是用平台无关的方式来做,这里最大的感触是,RN提供了一种途径,让js可以和原生组件交互,业务逻辑写在js里,利用原生组件呈现,如果有原生开发的同学支持,那么利用RN开发就方便多了,提供一致的组件库,一套代码就可以在两个系统上运行了,这样就不仅仅是learn once write anywhere了。

    关于性能优化:

    1、延迟加载

      如果一次加载太多的组件,RN需要等全部组件渲染完成才显示出来,会有白屏,所有每次加载组件最好少一些,比如先构建页面的框架,框架渲染完成后再加载数据,创建基于数据的组件,或者利用setTimeout延迟加载其他的组件。

    2、使用setNativeProps

      React把组件当成状态机,通常是用setState方法,改变组件状态,页面会重新渲染,但是重新渲染性能比较差,setNativeProps可以绕过这个过程,直接修改原生组件的属性,或者调用原生的组件的API,性能就好多了,但是状态同步方面就要多考虑下了。

    3、实现shouldComponentUpdate方法

      React在组件渲染时会有个diff算法,如果前后Virtual DOM状态改变,会重新渲染组件,如果实现shouldComponentUpdate方法,返回false,就会避免不必要的diff计算和渲染。

    关于React,这篇文章把他的前世今生都说了,写得很好:通往全栈工程师的捷径 —— react

    React真是无所不在了,React-DOM,React-Canvas,React-Native,看起来前途无量哇!

    最后,大家可以关注慢牛股票的微信公众号:

    发送react,可以获取demo的apk文件,安装体验。

     

    这个项目的源码后续会提交到github上,文章写的一般,见谅!欢迎大家评论留名^_^

    关于我的兼职创业历程

    慢牛系列一:如何抓取股票数据

    慢系系列二:前端技术选择

  • 相关阅读:
    px和rem换算
    使用Android Studio创建Android项目
    Hopscotch
    AtCoder Grand Contest 010 --C:Cleaning
    Hello world!
    概率生成函数
    FFT 学习笔记
    扩展中国剩余定理(excrt)
    组合恒等式
    常见数列
  • 原文地址:https://www.cnblogs.com/hongyin163/p/react-practice.html
Copyright © 2011-2022 走看看