reactnative_reactnative- - CSDN
  • ReactNative是由Facebook公司发布的可以进行混合开发的开源技术框架。通过ReactNative可以为iOS和Android两个系统开发应用程序,“Learn once,write anywhere”。使用ReactNative开发,既拥有Native的良好人机交互...
  • 刚刚度过了繁忙的一个月,连续不断的需求让自己有点招架不住了。写的代码质量有些堪忧,又导致不断的修改bug,陷入了恶性循环中了,不过随着最近最后一个需求即将完结,终于抽空写写rn相关的内容了。...

    刚刚度过了繁忙的一个月,连续不断的需求让自己有点招架不住了。写的代码质量有些堪忧,又导致不断的修改bug,陷入了恶性循环中了,不过随着最近最后一个需求即将完结,终于抽空写写rn相关的内容了。这个标题略有写浮夸,主要是为了吸引眼球,也有自己感受的原因。

    一、rn历史简介

    大家都知道rn是facebook开源的一个框架,不过关于rn的历史大家可能不太清楚。facebook在客户端2.0版本的时候,将大部分页面使用web技术实现,当时大概是2011年,android还在2.3版本、ios还在5.0版本。可想而知,结果当然是扑街了,在当时网页在手机上的体验相当的糟糕,用户吐槽声一片,facebook只能迅速的换成原生的实现。不得不说虽然是一次失败的尝试,但是facebook算是混合应用的先驱者和探索者,这也为后来facebook开发rn打下了基础。
    rn的idea是在2013年的一个极客大会上提出的,2014年7月facebook内部开始尝试使用这项技术,到了2015年3月,rn的ios版本正式开源,到了同年9月,rn的android版本也开源了。大概的发展历程如下:
    这里写图片描述
    rn虽然开源了接近了3年的时间了,但依然还没有到达1.0的正式版本,目前到了0.54版本,期待2021年1.0版本上线的时候…….不得不说,rn是历史上第一个没到正式版本,github却有6w+星星的项目,大写的服气。

    二、rn原理简介

    这里写图片描述
    盗了一张别人的android端架构图(侵删),rn的架构分为3层,java/oc层、c++层以及js层。这个结构和app内嵌h5基本一致,同样涉及到js和native通信等,只是将webview层替换为了c++层。

    三、前端上手rn

    1、rn对前端意味着什么

    我个人的理解是rn能帮助前端开发者使用熟悉的方式开发出一款接近原生体验的App,前提是你对react比较熟悉。接近原生体验要从两个方面来说这个问题,一个方面是rn的实现方式就决定了rn开发出的app只能是接近原生的体验,另一方面是前端同学一般对客户端开发不熟悉,在某些需要客户端方面进行支持优化的地方很难去处理。

    2、前端上手难度

    会React开发就能很快上手RN,还可以使用React全家桶哦。rn直接和react开发有很多相似的地方,同时也可以用是redux等react常用的第三方库,上手难度不大。

    3、前端遇到的小问题

    • 元素超过一屏不滚动
      web端的页面天生会滚动,如果元素超过了一屏就会出现滚动条,但是客户端上元素超过一屏是不会滚动的,需要在最外层套上一个能滚动的元素,比如scrollview或则listview等等。
    • ios和android的平台差异
      虽然rn尽量处理了android和ios两端之前的差异,但是还是两端还是有一些不一致的地方,比如有些控件的属性只在某一端能够使用,这个时候我们尽量避免使用这样的属性,采用两端效果能一致的实现方式来处理
    • 长列表的选择
      rn目前已经提供了listview和flatList两种长列表的方式,listview因为性能问题基本被放弃使用了,所以在选择长列表的时候尽量选择flatlist或者其他开源的列表组件。

    四、rn打开的正确方式

    这里写图片描述
    这是看到别人的博客上写的一段话,看了之后挺有感触的,因为自己在写rn的时候也觉得这是一个需要多方合作的一种开发模式。之前了解到携程好像将客户端和前端合并为大前端团队了,客户端和前端的同学一起协作开发。客户端的同学在app容器处理上肯定是最好的选择,但是一般在react开发上面不是很熟悉,前端同学明显在react的开发上比客户端同学更熟悉和了解,但是一般对客户端的开发比较陌生。双方可以完成自己更擅长的部分,同时可以相互学习各自领域的内容,这是一种极好的提升的方式。

    五、存在的问题

    1、不断更新的版本

    这里写图片描述
    这是rn版本的截图,3年时间已经更新了四十几个版本,不同版本之间差距还是挺大的,所以如何做好rn版本管理以及升级是一个非常重要的工作,主要是兼容性问题。

    2、问题排查困难

    这里写图片描述
    这是做rn经常会看到的一张图,大红的背景里提示你出现了错误,虽然说有调试工具可以帮助你定位错误,但是和web开发不同,rn报错有可能是前端爆的错误,也可能是客户端的错误,问题排查起来会比较苦难。

    3、长列表及动画性能不佳

    • 长列表快速滚动时会出现白屏的情况
      长列表快速向上滚动时,列表会出现白屏的情况。这主要是由于滚动时native和js频繁通信,导致客户端渲染不及时所导致的问题。目前还没有特别好的解决办法,有些公司会尽量避免在rn上使用长列表来规避这样的问题,如果列表内容比较简单的话,白屏出现的可能性会比较小。
    • 动画效果出现卡顿(特别是android手机上)
      rn的实现出来的动画会比较卡顿,原因和上一个问题基本相同。可能得解决方法是将动画完全由原生实现,js端直接使用原生动画,这样就可以避免动画卡顿的问题。

    4、首页白屏问题

    打包成Bundle包后一般会有几M,甚至十几M,导致首次渲染时白屏时间很长。
    在最新款的手机上,白屏的时间很短,然而在低版本的android手机上白屏时间缺非常的长。当然首页白屏问题现在已经有很多方案进行处理,比如拆包和预加载,这两种都是比较常见的处理方案了。

    5、优秀的热更新方案

    • 自搭还是第三方?
      一般公司都会选择自己搭建热更新框架,比较很少有公司愿意把这种更新的业务交由其他公司来完成,小公司的话可以尝试使用微软的热更新方案。
    • 如何做好兼容性处理?
      热更新也会导致兼容性问题,比如在之前的bundle包里没有这个功能,或者功能的结构发生变化,导致老版本无法正常使用新版本的内容。可能得解决方案有:
      1、控制版本,不兼容的版本就不进行热更新
      2、对客户端开方的接口进行封装,屏蔽客户端内部的实现
      3、不使用或者尽量少使用热更新方案,将rn作为一个类似原生模块嵌入到app中,每次发布版本才更新一次rn包
    • 傲娇的苹果
      苹果之前封杀过JSPatch等热跟新方案,没准苹果有出台什么规则不允许rn之类的热更新,所以也得做好心理准备。

    到这就写的差不用多了,最近rn的尝试也是挺有意义的,虽然开发流程等并没有太多新的东西,但是对rn开发流程、整体的结构等有了更深入的了解,之后准备再写写有关rn框架相关的东西,更深入的去了解这个框架。目前来说,rn还不是一个比较成熟的框架,在大型项目中的应用还需要更加谨慎的看待,所以最后点题,rn从入门到放弃,期待1.0版本的到来。

    over…

    展开全文
  • 写一个用reactnative 的项目 可以用于查看GitHub最受欢迎与最热项目的App。 项目开始 HomePage.js PS 可以先拖动到底部看下效果图 新建一个reactnative项目 ,底部因为有四个tab 选项卡 那么 我使用一个第三方组件...

    写一个用reactnative 的项目 可以用于查看GitHub最受欢迎与最热项目的App。

    https://github.com/liudao01/ReactNativeProject

    github地址 还在更新中

    项目开始 HomePage.js

    PS 可以先拖动到底部看下效果图

    新建一个reactnative项目 ,

    底部因为有四个tab 选项卡 那么 我使用一个第三方组件react-native-tab-navigator

    并且新建一个HomePage.js,关于第三方组件可以看下这篇文章 http://blog.csdn.net/true100/article/details/68066649

    这里单独说下 npm install react-native-tab-navigator --save 后面这个–save 这个的作用是用户把这个库加入到package.json中去.

    在Homepage.js里面 使用react-native-tab-navigatior

    这是 index.android.js

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View
    } from 'react-native';
    
    
    import Homepage from "./js/pages/HomePage";
    export default class testP extends Component {
      render() {
        return (
          <View style={styles.container}>
            <Homepage/>
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
      }
    });
    
    AppRegistry.registerComponent('testP', () => testP);
    
    

    这是 Hmepage.js

    /**
     * Created by liuml on 2017/9/8.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    } from 'react-native';
    import TabNavigator from 'react-native-tab-navigator';
    import TabNavigatorItem from "react-native-tab-navigator/TabNavigatorItem";
    
    export default class Homepage extends Component {
    
        // 构造
        constructor(props) {
            super(props);
            // 初始状态
            this.state = {selectedTab: 'papular'};
        }
    
    
        render() {
    
            return <View style={styles.container}>
                <TabNavigator>
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'papular'}
                        title="最热"
                        slectedTitleStyle={{color: '#FFF'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_popular.png')}></Image>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_popular.png')}/>}
                        onPress={() => this.setState({selectedTab: 'papular'})}>
    
                        <View style={{backgroundColor: '#FF0', flex: 1}}/>
                    </TabNavigator.Item>
    
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'trending'}
                        slectedTitleStyle={{color: '#0F0'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_trending.png')}/>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_trending.png')}/>}
                        onPress={() => this.setState({selectedTab: 'trending'})}
                        title="趋势">
    
                        <View style={{backgroundColor: '#0F0', flex: 1}}/>
                    </TabNavigator.Item>
    
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'favorite'}
                        slectedTitleStyle={{color: '#0F0'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_favorite.png')}/>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_favorite.png')}/>}
                        onPress={() => this.setState({selectedTab: 'favorite'})}
                        title="收藏">
    
                        <View style={{backgroundColor: '#0FF', flex: 1}}/>
                    </TabNavigator.Item>
    
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'my'}
                        slectedTitleStyle={{color: '#0F0'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_my.png')}/>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_my.png')}/>}
                        onPress={() => this.setState({selectedTab: 'my'})}
                        title="我的">
    
                        <View style={{backgroundColor: '#FFF', flex: 1}}/>
                    </TabNavigator.Item>
    
                </TabNavigator>
            </View>
    
        }
    }
    
    const styles = StyleSheet.create({
    
        container: {
            flex: 1
        },
        icon: {
            width: 26,
            height: 26
        }
    
    });
    
    

    解释:

    我这里拿出一个item 出来解释

    renderSelectedIcon 这是选中后的图片
    tintColor 是给图片渲染
    title 就是名字
    我在构造函数中定义了一个变量selectedTab 让他默认是最热

    // 初始状态
    this.state = {selectedTab: ‘papular’};

    然后在item中判断selected={this.state.selectedTab === ‘papular’} 值是否为最热

    通过selected 判断是否选中状态 根据值是否相等

    在onPress 点击事件 里面给他重新设置值

    在每个item 中间可以看到我填充了一个view

    <View style={{backgroundColor: '#FF0', flex: 1}}/>
    
    

    这个就是作为填充的视图

    
            
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'papular'}
                        title="最热"
                        slectedTitleStyle={{color: '#FFF'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_popular.png')}></Image>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_popular.png')}/>}
                        onPress={() => this.setState({selectedTab: 'papular'})}>
    
                        <View style={{backgroundColor: '#FF0', flex: 1}}/>
                    </TabNavigator.Item>
    

    然后 看下效果图

    image


    最后看下这个第三方库react-native-TabNavigator的item的源码 直接在import哪里点击引入就好(android studio
    怎么点这里就怎么点)

    
    export default class TabNavigatorItem extends React.Component {
      static propTypes = {
        renderIcon: PropTypes.func,
        renderSelectedIcon: PropTypes.func,
        badgeText: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
        renderBadge: PropTypes.func,
        title: PropTypes.string,
        titleStyle: Text.propTypes.style,
        selectedTitleStyle: Text.propTypes.style,
        tabStyle: ViewPropTypes.style,
        selected: PropTypes.bool,
        onPress: PropTypes.func,
        allowFontScaling: PropTypes.bool,
      };
    
      static defaultProps = {
      };
    
      render() {
        let child = React.Children.only(this.props.children);
        return React.cloneElement(child, {
          style: [child.props.style, this.props.style],
        });
      }
    }
    
    

    可以看到 renderIcon renderSelectedIcon 等等的声明都在这里


    最热页面 PapularPage.js : 以及导航栏 NavigationBar.js

    说下对应关系 homepage 里面包含了最热页面 PapularPage.js 最热页面里面包含了导航栏 NaivgationBar.js

    关于react native 布局 这篇文章很不错错 http://www.jianshu.com/p/688b9108a922

    先写NavigationBar.js

    
    /**
     * Created by liuml on 2017/9/11.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        StatusBar,
        Platform,
        Image,
        TouchableOpacity
    } from 'react-native';
    
    export default class NavigationBar extends Component {
    
        render() {
            return <View style={styles.container}>
                <View style={styles.container}>
                    <StatusBar hidden={false} barStyle="light-content"/>
                </View>
                {/*顶部导航栏*/}
                <View style={styles.navBar}>
                    <View style={styles.navBar}></View>
                    <View style={styles.titleWrapper}>
                        <Text style={styles.title}>热门</Text>
                    </View>
    
                    <View style={styles.rightBar}>
                        <TouchableOpacity activeOpacity={0.7}>
                            <Image source={require('../../res/images/ic_search_white_48pt.png')}></Image>
                        </TouchableOpacity>
                        <TouchableOpacity activeOpacity={0.7}>
                            <Image source={require('../../res/images/ic_more_vert_white_48pt.png')}></Image>
                        </TouchableOpacity>
    
                    </View>
                </View>
            </View>
        }
    }
    const styles = StyleSheet.create({
    
        container: {
            backgroundColor: '#63B8FF',
        },
        statusBar: {
            height: Platform.OS === 'ios' ? 20 : 0
        },
        navBar: {
            flexDirection: 'row',
            justifyContent: 'space-between',
            alignItems: 'center',
    
        },
        titleWrapper: {
            flexDirection: 'column',
            justifyContent:'center',
            alignItems:'center',
            position:'absolute',
            left:40,
            right:40,
        },
        title: {
            fontSize: 16,
            color: '#FFF'
        },
        rightBar: {
            flexDirection: 'row',
            alignItems: 'center',
            paddingRight:8
        }
    });
    
    
    

    看下效果图

    mark

    分析 从样式分析

    statusBar

    NavigationBar 会包含状态栏,还有顶部导航栏 状态栏用到一个控件 StatusBar (ios用的)

    注意这里ios和android 稍微有点不同了ios StatusBar 有效果 就是显示顶部的状态栏.安卓没效果

    关于状态栏说下 ios 可以使用 android 无效果 所以得区分下 这里我使用了Platfrom 判断是ios 还是android

    navBar

    flexDirection: ‘row’, 让主轴方向是横向

    justifyContent: ‘space-between’, 让主轴排列方式是在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首

    对齐,每行最后一个元素与行尾对齐。( 这里面有个技巧: 因为控件只有三个

    会造成热门文字不在中间, 那么我就在最左边再添加一个view )

    titleWrapper

    flexDirection: ‘column’, 让主轴方向是纵轴

    justifyContent: ‘center’, 主轴排列方式居中

    alignItems: ‘center’, 交叉轴的排列方式也是居中的

    position: 'absolute',
        left: 40,
        right: 40,   
    

    说下为什么这里需要position ,可以尝试下不加position 会造成热门并不在中间.那么就给他使用position 并且微调下

    position enum(‘absolute’,‘relative’)属性设置元素的定位方式,为将要定位的元素定义定位规则。

    absolute 生成绝对定位的元素,元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。

    relative:生成相对定位的元素,相对于其正常位置进行定位。因此,“left:20” 会向元素的 LEFT 位置添加 20 像素。

    title

    没啥说的就是设置了颜色和大小

    navBtn

    也没啥说的 就是给设置了宽高 右边的搜索和更多的图片宽高

    rightBar

    包裹右面两个图片的样式

    flexDirection: ‘row’, 主轴方向横向

    alignItems: ‘center’, 主轴对齐方式居中对齐

    paddingRight: 8 居右8?  我不清楚这个是dp 还是像素
    

    TouchableOpacity(透明度变化)

    TouchableOpacity组件介绍
    该组件封装了响应触摸事件。当点击按下的时候,该组件的透明度会降低。该组件使用过程中

    并不会改变视图的层级关系,而且我们可以非常容易的添加到应用并且不会产生额外的异常错误。

    创建 PapularPage.js 里面包含了NavigationBar.js

    /**
     * Created by liuml on 2017/9/11.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    }from 'react-native';
    
    import NavigationBar from "../compoent/NavigationBar.js"
    export default class PapularPage extends Component {
    
        render() {
            return <View style={styles.container}>
                <NavigationBar/>
            </View>
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1
        }
    });
    

    没啥说的 非常简单就是把NavigationBar加入到了这个Papular页面

    把上面的做好之后的效果图就是我上面的效果图


    OK 下面在PapularPage页面内添加 可以左右滑动的控件(选项卡控件)

    react-native-scrollable-tab-view

    用到一个第三方组件 http://www.jianshu.com/p/b7788c3d106e

    上面有使用方式 我把他引入我的项目

    
    /**
     * Created by liuml on 2017/9/11.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    }from 'react-native';
    
    import NavigationBar from "../compoent/NavigationBar.js"
    import ScrollableTabView from "react-native-scrollable-tab-view"
    export default class PapularPage extends Component {
    
        render() {
            return <View style={styles.container}>
                <NavigationBar/>
                <ScrollableTabView
                    tabBarBackgroundColor="#63B8FF"
                    tabBarActiveTextColor="#FFF"
                    tabBarInactiveTextColor="#F5FFFA"
                    tabBarUnderlineStyle={{backgroundColor: "#E7E7E7", height: 2}}>
                    <Text tabLabel='IOS'/>
                    <Text tabLabel='Android'/>
                    <Text tabLabel='Java'/>
                    <Text tabLabel='JavaScript'/>
                </ScrollableTabView>
            </View>
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1
        }
    });
    
    

    mark

    比较简单没啥说的.

    现在的数据是写死的 后面会动态改变

    tabBarUnderlineStyle(style)
    设置DefaultTabBar和ScrollableTabBarTab选中时下方横线的颜色

    tabBarBackgroundColor(String)
    设置整个Tab这一栏的背景颜色

    tabBarActiveTextColor(String)
    设置选中Tab的文字颜色

    tabBarInactiveTextColor(String)
    设置未选中Tab的文字颜色

    tabBarTextStyle(Object)
    设置Tab文字的样式,比如字号、字体等


    下面是关于布局的总结:

    容器的属性

    flexDirection

    flexWrap

    justifyContent

    alignItems

    项目的属性

    flex

    alignSelf

    flexDirection属性

    flexDirection属性决定主轴的方向(即项目的排列方向)。
    它可能有4个值:

    row:主轴为水平方向,起点在左端。

    row-reverse:主轴为水平方向,起点在右端。

    column(默认值):主轴为垂直方向,起点在上沿。

    column-reverse:主轴为垂直方向,起点在下沿。

    flexWrap属性

    默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。它可能取三个值。

    (1)nowrap(默认):不换行。

    (2)wrap:换行,第一行在上方。

    justifyContent属性

    justify-content属性定义了项目在主轴上的对齐方式。

    它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。
    flex-start(默认值):左对齐

    flex-end:右对齐

    center: 居中

    space-between:两端对齐,项目之间的间隔都相等。

    space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

    alignItems属性

    align-items属性定义项目在交叉轴上如何对齐。
    它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

    flex-start:交叉轴的起点对齐。

    flex-end:交叉轴的终点对齐。

    center:交叉轴的中点对齐。

    baseline: 项目的第一行文字的基线对齐。

    stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

    flex属性

    flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

    flex-grow属性

    flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

    如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

    alignSelf属性

    alignSelf属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。

    默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

    该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

    展开全文
  • 投稿 | 亦枫责编 | 唐小引Udacity 移动端团队最近删除了 App 中使用 React Native 语言开发的相关功能。我们收到大量有关我们用法或 React ...
        

    640?wx_fmt=gif

    640?wx_fmt=png

    投稿 | 亦枫

    责编 | 唐小引

    Udacity 移动端团队最近删除了 App 中使用 React Native 语言开发的相关功能。

    我们收到大量有关我们用法或 React Native 的问题以及为什么我们停止投入资源和精力在 RN 上。

    在这篇文章中,我希望能够回答我们收到的大多数问题并深入了解:

    • 我们团队的规模和组成是什么?

    • 为什么我们优先考虑尝试 React Native?

    • 放弃的原因是什么?

    • 什么有用?什么没有?

    • ……还有更多

    我当然不会声称自己是 React Native 的专家。我们团队中的其他人比我有更有经验,但我相信他们也不会自称专家。

    我将根据我们自己的经验谈论在我们的特定情况下做什么和不做什么。至于 React Native 是否适合你的团队/项目取决于你,但希望这篇文章能够提供额外有用的数据点供你参考。

    “React Native 是否适合你的团队/项目取决于你。”

    我还是想指出,这些经验和意见来自 Udacity 的移动工程团队,而不是其他任何人。这里的想法并不反映任何其他团队使用或构建 React 或 React Native 内容的意见。


    640?wx_fmt=png

    团队


    首先要搞清楚的事情。我们的团队是什么样的?团队规模,经验和所在组织有能力将 React Native 的可行性在项目中产生实际影响。

    我们的移动端团队分布在 iOS 和 Android 平台上。

    一、团队规模

    最初引入 React Native 时:

    • 1 名 iOS 开发

    • 2 名 Android 开发

    • 1 名产品经理

    • 1 名设计师

    到了今天:

    • 4 名 iOS 开发

    • 3 名 Android 开发

    • 1 名产品经理

    • 1 名设计师

    在我们使用 React Native 长达 18 个月的过程中,我们的 iOS 和 Android 团队的规模都在保持增长。

    团队更由一位新的产品经理负责。

    我们通过多名设计师和设计范例进行过转型。

    二、开发背景

    引入 React Native 时,使用 JavaScript 和 React 范例的每个团队有多舒适?

    • iOS

    iOS 团队的唯一开发人员之前拥有丰富的 Javascript 和 Web 开发经验,非常乐意使用 React Native 开发。

    如今,四个 iOS 开发者中至少有三个习惯并适应使用 Javascript 和 React Native 技术。

    • Android

    在引入 React Native 时,两位 Android 开发人员中有一位对 Javascript 感到满意。另一位(也就是我自己)只有很少的 Javascript,React 或 web 开发背景。

    后来加入团队的其他 Android 开发人员也几乎没有 Javascript 或 Web 经验。


    640?wx_fmt=png

    我们的 Apps


    我们的产品是做什么的?

    我们的手机应用旨在为将 Udacity 学习体验带到你的手机设备上。它们支持身份验证,内容发现,程序注册(在某些情况下还有支付),最后支持各种程序和内容类型的学习材料的消费。

    这些应用也是新的实验性功能和计划的试验场所,目的在于改善用户的整体学习效果。

    一、代码库规模

    • iOS:97,400 行(.swift,.h,.m 格式)

    • Android:93,000 行(xml,java,kotlin,gradle)

    二、同等

    引入 React Native 后,应用程序的功能也非常接近。

    随着时间的推移,核心体验大致相当,但每个团队都增加有或多或少的对另一个平台的经验。

    此外,由于国际需求的扩大,本地化和更小的 apk size 等成为 Android 团队越来越重视的事情。Android 团队还与其他地区的团队密切合作,针对非 iOS 需要考虑的市场特定功能。


    640?wx_fmt=png

    为什么以及我们如何采用 RN


    一、我们为什么要引入?

    我们开始推出全新的移动端专有功能。我们希望在两个平台上快速进行实验和验证,因此跨平台开发非常具备吸引力。

    因为它是一个新的并且独立的功能,所以被认为是尝试跨平台开发的契机。

    选择 React Native 有几个原因:

    • 作为跨平台解决方案提高了可行性;

    • 大多数(2/3 的开发人员)团队适应 Javascript 和 Web 开发;

    • 提高了开发速度;

    • 来自公司外其他团队的成功经验。

    二、我们是如何引入的?

    最初的 React Native 功能是在一个单独的 GitHub 仓库中构建的,并作为 Git 子分支分别并入 iOS 和 Android 仓库。

    这样可以实现非常快速的原型设计,并且如果需要,可以将该功能作为独立产品发布。

    更多的经验是原型,最终我们在 React Native 代码库中引入了第二个更大的功能。

    三、时间线

    • 2016 年 8 月:为功能 1 创建 React Native repo

    • 2016 年 11 月:Android 平台发布功能 1

    • 2016 年 11 月:功能 2 开始开发

    • 2016 年 12 月:功能 3 开始原型设计

    • 2017 年 1 月:功能 1 开发结束

    • 2017 年 2 月:功能 2 发布

    • 2017 年 3 月:功能 3 原型设计结束

    • 2017 年 11 月:Android 更新功能 2

    • 2017 年 12 月:功能 4 原型作为独立应用程序。由于性能问题,最终取消了对原生的支持

    • 2018 年 2 月:iOS 更新功能 2

    • 2018 年 4 月:功能 1 从 Android 平台中删除

    • 2018 年 6 月:从两个应用中删除功能 2


    640?wx_fmt=png

    去除的动机?


    答案直截了当。

    我们从应用程序中删除最后的 React Native 代码,因为唯一剩下的 React Native 开发的功能已经下线,我们不再需要支持。

    一、“为什么我们停止投入 React Native ?”

    这是一个更有趣的问题。

    想到下面几点原因:

    • 同时在两个平台上开发的功能数量减少;

    • Android 特定产品需求的增加;

    • 对长期维护成本感到失望;

    • Android 团队不倾向继续使用 React Native。


    640?wx_fmt=png

    我们用什么取而代之?


    我们已经部署和删除的 React Native 相关功能不再需要支持,自然不需要替代者。


    640?wx_fmt=png

    好的方面?


    我们进军 React Native 的哪些方面进展顺利?

    • 入手 React Native 开始在两个平台上构建运行确实非常简单

    • 能够从更庞大的 React 和 Javascript 生态系统中提取使用很多现有的 librayies 和工具

    • 我们能够同时在两个平台上对功能 1 进行原型设计

    • 跨平台团队的单个开发人员能够同时为两个平台构建大部分功能 2

    • 团队对 React Native 的共同理解有所加深


    640?wx_fmt=png

    我们遇到哪些问题?


    在我们使用 React Native 期间,我们遇到了许多问题。其中一些归因于我们的工作流程,一些归因于我们的用例,而另一些则归因于 React Native 本身。

    一、设计和体验的挑战

    • 平台一致的 UI / UX

    因为我们将一些新的屏幕集成到现有更大的用户体验当中,所以我们希望新的 React Native 代码能够遵循原生平台模式和现有样式。这意味着我们不一定能为两个平台使用相同的 UI 设计。

    在 React Native 中确保每个平台自身的样式并不困难,但它确实需要了解每个代码库中使用的设计范例。最简单的是,这需要平台检查以及每个系统的自定义小部件。

    对于我们来说,这通常需要与每个平台的开发人员和设计人员沟通,来了解所需要的内容,或者两者都使用单一样式。这通常会导致 Android 方面的体验与其他应用截然不同。

    一些更复杂的情况下,需要额外的开发平台特定代码来自定义应用体验。

    这样的例子之一是确保返回/前进按钮图标的适配。由于需要将新的 React Native 功能集成到现有应用当中,为确保返回/前进图标和返回按钮按下的正确行为,需要针对 React Native 代码库修改 Android 特定原生代码。

    • 原生设计的更改可能需要更改 React Native 代码以处理集成点

    不止一次,Android 应用的导航结构发生变化,这要求我们更新 React Native 代码。

    React Native 功能不必被隔离到自己的 Activity 中,而是必须移动到一个 fragment 中,放置在一个带有 BottomNavigationView 的屏幕中,然后在它自己和其他原生 fragments 之间协调。

    这种类型的平台修改需要返回到单独的代码库,进行更改,更新集成,并确保新修改也不会对 iOS 平台产生负面影响。

    • 设备特定问题

    “碎片化”也好,“多样化”也罢,不论你怎么称呼,留给我们一个不争的事实是有更多独特的 Android 设备配置需要特殊考虑。

    我们多次发现布局不适应不同尺寸的 Android 手机。我们发现在最新的 iPhone 或 Pixel 设备上运行流畅的动画,在 Android 广泛使用的国际市场的低端设备上却运行不佳。

    这些肯定不是唯一的 React Native 问题;这些是 Android 上常见的开发挑战,但随着平台特定检查和考虑因素的增加,我们不得不开始考虑使用 React Native 实际节省了多少时间。

    • 全球增长

    在我们使用 React Native 的过程中,国际化成为 Android 团队的一个更大的挑战。我们有几个国际办事处要求实现本地化并减少 apk 大小。

    React Native 中的字符串本地化可以完成,因为它确实需要额外的设置。在我们的例子中,它需要更改单独的仓库。这增加了本地化任务的复杂性,这在寻求其他团队的本地化帮助时并不理想。这直接减少了 React Native 功能的本地化频率。

    我们能够在这段时间减少我们的 apk 大小,但是包含 React Native 的代码规模相当大,我们无法解决这些问题。删除最后一个 RN 功能后,我们的 apk 减小 10M 左右,包括资源删除和 React Native 本身的剔除。

    二、集成挑战

    • 与原生组件和导航结构集成

    根据我们的经验,如果是一个独立的功能,将 React Native 集成到现有应用程序中可能非常简单,然而如果需要与现有组件紧密集成并与之通信,则可能会遇到一些挑战。

    我们发现自己经常需要大量的桥接代码实现原生和 React Native 组件之间的通信。当我们需要更改 React Native 组件适应我们的导航层次结构的位置时,相关代码至少需要一次更新。

    • 工具/构建问题

    将 React Native 所需的更新合并到每个应用的构建过程中。我们使用 CircleCI (持续集成工具)来构建我们需要重新配置的项目,以支持额外的 React Native 构建步骤。

    就像前面说的那样,在 Android 方面,这并不像我们想象的那样简单。

    一旦我们的构建需要更新包含所需的 React Native 任务时,CircleCI 的发布编译时间增加大约 20%。

    从我们的代码库中删除最终的 React Native 功能后,我们看到了以下提升:

    1. CircleCI 编译时间从 15min 减少到 12min 左右

    2. 发布 apk 大小从 28.4MB 降低至 18.1MB

    Android 团队也遇到过 Android/Gradle 构建工具与 React Native 冲突的问题。最近我们一直在解决 Gradle 4 版本的问题。

    iOS 团队也面临着相当大的挑战。

    配置构建非常痛苦,因为我们的 React Native 的文件结构并不标准。鉴于我们独立的项目仓库,我们从 srcroot/ReactNative 拉取 React Native 代码,并且许多现有的构建工具采用了默认的 app 结构,即 /ReactNative/ios/... ios。

    此外,我们使用 cocoapods 进行依赖管理,这是最初建议的融入 React Native 的方式,但在后续已被弃用。我们非标准的文件结构进一步加剧这种情况,导致我们不得不在 Podfile 中包含一些令人讨厌的黑客式操作,以便能从正确的位置读取到。

    由于 cocoapods 不再是包含 React Native 的规范方式,因此 Podfile 更新依赖于要社区去更新,这并不总是同步的。在几个版本中,css/Yoga 依赖更新掉了,但是 Podfile 却引用了一个不正确的版本... 最后没办法,我们使用一些黑科技手段解决这种问题。

    最后,iOS 项目的 CI(持续集成)也是一个痛点。我们现在必须添加一个 npm 依赖层,并确保在继续安装之前正确更新它们。这为我们的构建步骤增加大量的时间。

    还有一个引发崩溃的问题,因为一个包含 package.lock 文件的 npm 版本,而另一个版本没有包含,导致我们在 React Native 升级过程中安装了不正确的依赖版本。


    640?wx_fmt=png

    React Native 挑战


    一、文档

    React Native 作为一个生态一直在快速发展,我们发现文档经常跟不上。特别是在我们首次采用时,我们发现特定版本的文档/答案可能关联不上。

    关于集成 React Native 到现有项目的文档在当时似乎很少。这是我们更新 CI 构建所面临挑战的一个因素。

    随着 React Native 不断发展,文档和支持社区的贡献得到了改善。如果我们今天开始,我们可能会更容易找到一些问题的答案。

    二、导航

    我们最初使用的是 NavigationExperimental,它不是最容易使用的导航库。当 ReactNavigation 出现时,它迅速成为社区广泛接受的导航,并且在 ReactNavigation 真正完全成熟之前 NavigationExperimental 已经被废弃。

    三、性能

    如前所述,有些时候会注意到一些性能问题。

    我们能够制作一些非常漂亮的动画,这些动画在规范的 iOS 和 Android 设备上看起来非常不错,但在国际市场上比较普遍的低端 Android 设备上却表现不佳。

    进入应用的 React Native 部分时,加载时间比我们想要的要长。看上去往往不像是无缝过渡。

    在对独立功能 4 进行原型设计时,绘制渲染性能是一个非常大的问题,以致 React Native 被放弃来达到支持原生体验。

    四、滞后于原生平台

    因为它不是与 iOS 或 Android 一起构建的,所以 React Native 有时会落后于原生平台。它通常很大程度上依赖于社区来支持新的原生功能。

    其中一个例子就是迫切需要为 iPhone X 设备提供 SafeArea 支持。我们最终选择在短时间内不使用 SafeArea 支持该功能。使用 SafeAreaView 是跨平台开发人员需要了解的开发兼容应用程序的平台特定功能的一个示例。

    在其他时候,React Native 在采用新平台要求方面落后,例如要求在 2018 年 8 月之前针对 api 26 开发 Android 应用程序。这个需求尚有几个未解决的问题。

    五、打破更新

    React Native 的非向后兼容升级非常令人沮丧。一个例子是当 React Native 升级它的底层 React 库时 PropType 被弃用。

    如果不再维护我们自己的自定义分支,许多第三方库就会变得无法使用。


    640?wx_fmt=png

    维护挑战


    维护代码库的 React Native 部分有时对我们来说是一个挑战。如前所述,Android 通常需要额外的工作,无论是与现有代码集成还是修复 UI 适配问题。这导致 iOS 和 Android 在 React Native 代码库的不同分支上工作,因此一个平台不会减慢另一个平台的步伐。

    由于这种分支,代码的分歧开始慢慢形成,并且使它们达到奇偶校验所需的努力有所增加。结果,对一个平台的更新没有立即添加到另一个平台。

    React Native 的变化速度也带来了挑战。由于可能会破坏更改,因此更新依赖项以获取新功能或错误修复并不总是很快。

    同样,有时这会导致冲突增加,从而减慢代码的维护速度。由于团队规模小,精力有限,如果它不是 React Native 代码中的简单/快速修复,由于可能需要额外的开发工作,它的处理可能性要低得多。

    添加 React Native 之后,并不总是清楚错误存在于什么级别。它是否存在于两个平台中?还是只在一个平台上?如果仅在一个平台上,是在原生代码还是 React Native 代码中?这些问题增加的复杂性有时会减慢质量保证过程。

    当需要修复代码库的 React Native 部分中的问题时,我们现在必须同时考虑 iOS 和 Android,并且可能使用 3 个开发堆栈而不是 1 个。

    此外,只有不到 100%的团队感觉 React Native 效率很高,能够迅速进入并修复某些东西的开发人员的数量也减少了。


    640?wx_fmt=png

    我们能够做些什么?


    我相信我们遇到的一些问题是我们的用例所特有的,但是我们可以做些不同的事情来缓解其中的一些问题。

    一、减少分歧

    我们本可以更好地保持每个应用程序与 React Native repo 中的最新更改保持同步。我相信保持这些更新同步将有助于增强我们为这些功能开发更强的真正的跨平台开发。

    在更多的设备上测试,特别是在 Android 上,这样能够在早期发现更多 UI / 性能问题,并允许我们在上线之前修复它们。通过在新需求开始工作之前解决问题,这也可以减少代码分歧的数量。

    二、更一致的设计

    从一开始就更具体的设计方案可能会改善功能的原生外观。其中一个具体示例是使用与其他原生应用程序一致的文本/边距值,而不是在新体验中选择新值并在两个平台上使用它。

    三、更好的团队理解

    对 React Native 不太熟悉的团队成员可能已经做了更多努力以适应额外的开发任务。这会增加能够快速解决代码问题的人数。


    640?wx_fmt=png

    是否有我们认为更合适的用例?


    我相信我们团队中没有任何人认为 React Native 没有它的优点。我当然相信 React Native 非常适合用例。

    • 你是否需要在两个平台上快速从头开始构建/构建新应用程序?

    • 你是否正在构建一个应用程序/功能,无论平台如何,其外观/行为都相同?

    你有没有想要为移动设备贡献的备用开发周期的 Javascript 开发人员?

    如果对这些问题中的任何一个回答“是”,React Native 可能是你的可行性选择。

    特别是,我认为如果你有 Javascript/React 的背景,并且正在寻找构建一个不需要太多原生代码的应用程序,那么 React Native 是一个非常有吸引力的选择。它将使您能够开始在移动设备上构建,而无需学习 2 种不同的技术栈。

    对于完全跨平台应用程序的开发,React Native 也是一个很好的选择。


    640?wx_fmt=png

    我们会再次使用 React Native 吗?


    iOS 和 Android 团队在这方面意见不一。

    一、iOS

    有可能。iOS 团队通常很高兴与 React Native 合作,并考虑使用它构建新功能。此外,在产品方面,我们产品经理对在 iOS 上运行的 React Native 解决方案比对 Android 更有信心。

    二、Android

    不会。理想情况下,Android 团队将来不会投入精力到 React Native。我们发现与 React Native 组件集成的过程很麻烦,并且感觉到所有 Android 设备的体验都不是很好。

    此外,还有一种倾向于坚持单一开发技术战的感觉,而不是在 Android 框架之上添加新的抽象层和可能的 bugs。

    我们的感觉是,React Native 在 Android 上运行新功能的速度更快,但从早期阶段到完美版本再到长期维护需要更长的时间。


    640?wx_fmt=png

    我们会再另一种跨平台解决方案吗?


    作为一个团队,我们可能不会在不久的将来投入跨平台开发。iOS 团队可以使用 React Native 构建一些东西,并且仍然限定于 iOS,因为他们团队通常更喜欢这种体验。

    个人而言,团队成员会继续关注 React Native 和 Flutter。随着 React Native 和 Flutter 等解决方案的不断发展,我们将继续为我们的团队评估它们。


    640?wx_fmt=png

    总结

    这就是我们今天所处的境地。

    我们对 React Native 如何适应我们的团队和路线图有了更好的理解。我们可以利用这些信息为我们团队的正确技术选择做出明智的判断。

    “我们能否明确地说出 React Native 是否适合你?没有。”

    我们看到了 React Native 的优点以及局限性。我们能否明确地说出 React Native 是否适合你?

    没有。

    但是,在评估 React Native 是否适用于你的项目时,希望我们的经验可以作为帮你带来一些额外参考点。

    声明:本文为作者投稿,版权归作者所有,如需转载,请联系原作者。

    640?wx_fmt=jpeg


    征稿啦

    CSDN 公众号秉持着「与千万技术人共成长」理念,不仅以「极客头条」、「畅言」栏目在第一时间以技术人的独特视角描述技术人关心的行业焦点事件,更有「技术头条」专栏,深度解读行业内的热门技术与场景应用,让所有的开发者紧跟技术潮流,保持警醒的技术嗅觉,对行业趋势、技术有更为全面的认知。

    如果你有优质的文章,或是行业热点事件、技术趋势的真知灼见,或是深度的应用实践、场景方案等的新见解,欢迎联系 CSDN 投稿,联系方式:微信(guorui_1118,请备注投稿+姓名+公司职位),邮箱(guorui@csdn.net)。


    ————— 推荐阅读 —————

    640?wx_fmt=jpeg

    640?wx_fmt=jpeg

    640?wx_fmt=png

    640?wx_fmt=gif

    640?wx_fmt=gif

    展开全文
  • 2015年9月15日,Facebook发布了 React Native for Android,把 Web 和原生平台的 JavaScript 开发技术扩展到了 Google 的流行移动平台。什么是React NativeReact Native 让开发者使用 JavaScript 和 React 编写应用...

    2015年9月15日,Facebook发布了 React Native for Android,把 Web 和原生平台的 JavaScript 开发技术扩展到了 Google 的流行移动平台。


    什么是React Native

    React Native 让开发者使用 JavaScript 和 React 编写应用,利用相同的核心代码就可以创建 Web,iOS 和 Android 平台的原生应用。React Native 的宗旨是,学习一次,高效编写跨平台原生应用。

    官方的github地址为:https://facebook.github.io/react-native/


    React Native有什么优点

    1.提供了原生的控件支持

    使用 React Native 你可以使用原生的控件,入在iOS平台我们可以使用UITabBar控件,在Android平台我们可以使用Drawer控件。这样,就让我们的App从使用上和视觉上拥有像原生App一样的体验。而且使用起来也非常简单。

    2.异步执行

    所有的JavaScript逻辑与原生的代码逻辑都是在异步中执行的。原生的代码逻辑当然也可以添加自己的额外的线程。

    这个特性意味着,我们可以将图片解码过程的线程从主线程中抽离出来,在后台线程将其保存在磁盘中,在不影响UI的情况下计算调整布局等等。

    所以,这些让React Native开发出来的App都是较为的流畅。

    这个之间的通信过程也是有序列化来完成的,这个就让我们可以使用Chrome Developer Tools 来完成JavaScript逻辑的调试,当然我们也能够在模拟器和物理设备上调试。

    3.触屏处理
    React Native实现了高性能的图层点击与接触处理。

    4.Flexbox的布局样式
    使布局将变得更简单,这就使我们为什么要将网页的布局模式切换到React Native的Flexbox布局模式。Flexbox让UI布局变得简单,入使用margin和padding的嵌套模式。当然,React Native 同样也支持网页原生的一些属性布局模式,如FontWeight之类的。这些声明的布局和样式,都会存在内联的机制将其优化。

    5.Polyfills机制
    React Native也支持我们使用第三方的JavaScript库,来方便我们的开发。支持npm中的成千上万的模块。

    6.基于React JS
    拥有React JS的优良特性。


    跨平台框架这么多?为什么重点关注React Native?

    如我们之前所介绍的,Android与IOS跨平台开发框架如此这多,如之前我们介绍的PhoneGap、Xamarin等,为什么我们重点的关注React Native呢?

    1. Facebook所开源的框架
      我们知道,所有的开源框架,只有是一线的大公司研发出来的才能够保证框架的维护性、可用性。当然,这样也会吸引更多的开发者使用这个框架,才能够使我们在人才储备上有人可用。并不是说,框架多好就能够用的。如国内的CrossApp,虽然很好用,但是知名度不够,造成我们研发、bug反馈、人才招聘上的种种窘境。

    2. React JS技术的革命
      这个东西也就是国内的很多跨平台框架没有关注的地方,Facebook使用了React JS已经有了好几年的技术变革,特别是JSX与Virtual DOM的加入,给使用JavaScript来开发Native App简直是一个质的飞跃。

    3. BAT团队已经投入研发与使用
      如果很多中小型公司,看不清方向,这个我们倒是可以模仿BAT的脚步。现在的BAT公司内部,特别是A,已经投入了大量的人力在React Native上面,听说TMall App已经开始使用React 进行重构。

    我们可以看到,目前对于Facebook来说,他们的新业务线也将直接使用了React Native的开发模式


    搭建React Native 的 Windows 环境

    NodeJs、Python、Android SDK、JDK

    由于我们大天朝网络的限制,很多依赖的库都fetch不下来。所以整个React Native的环境搭建,命令执行都是一个痛苦的过程。(就连NodeJS我都快下了半天的时间)

    我在Windows平台上搭建环境弄了差不多一周的时间,都没有弄下来,特别是下面这个问题一直困扰着我

    bash: ulimit: open files: cannot modify limit: Too many open files

    后面得到了高人的指点,借给我了一个梯子,并在我的Mac设备上成功的运行了自己的第一个React Native项目。哭~~~

    下面是我的运行步骤,大多数是和官方的介绍一样的:

    我们先从Github上获取React Native的代码

    github地址:https://github.com/facebook/react-native

    git clone https://github.com/facebook/react-native.git

    进入React Native 并使用npm 进行安装

    npm install -g react-native-cli

    注意
    - 使用npm进行安装,需要搭建好完整的nodejs环境,nodejs地址:https://nodejs.org
    - npm install 需要依赖于很多国外资源,自备翻墙梯子


    新建自己的React Native项目,这里命名为AwsomeProject

    react-native init AwsomeProject

    运行完后,如果环境变量没有配置错误,react 将会帮我们生成一个AwsomeProject的文件夹目录。

    里面内如如下所示:


    运行Android App

    $ cd AwesomeProject
    $ react-native run-android

    看起来很简单的两句命令,但是里面隐藏这很多的陷阱。
    - 确保Gradle的环境配置好了,这里还会动态的down很多Gradle的依赖文件,不翻墙估计依赖文件都下不下来
    - 需要安装好自己的Python环境(怎么安装google吧),React Native 的 packager需要 python的支持
    - 这个东西,只能运行在Android模拟器上,真机运行必须失败,至于为什么后面在介绍

    注意好上面三点,就能在模拟器上看到如下画面了


    运行iOS App

    ios相对就简单了很多,直接打开 ios/AwesomeProject.xcodeproj 文件,使用Xcode编译运行就能出现和Android类似的界面了。我的效果如下:

    注意,同样只能够在模拟器上运行

    React Native的优势和劣势:(转):

    React Native的优势

    相对Hybird app或者Webapp:

    • 不用Webview,彻底摆脱了Webview让人不爽的交互和性能问题
    • 有较强的扩展性,这是因为Native端提供的是基本控件,JS可以自由组合使用
    • 可以直接使用Native原生的「牛逼」动画(在FB Group这个app里面,面板滑出带一点果冻弹动,面板基于某个点展开这种动画随处可见,这种动画用Native code来做小菜一碟,但是用Web来做就难上加难)。

    相对于Native app:

    • 可以通过更新远端JS,直接更新app,不过这快成为各家大型Native app的标配了…

    劣势

    • 扩展性仍然远远不如web,也远远不如直接写Native code(这个不用废话解释了吧)
    • 从Native到Web,要做很多概念转换,势必造成双方都要妥协。最终web要用一套CSS的阉割版,Native要费劲地把这个阉割版转换成native原生的表达方式(比如iOS的Constraint\origin\Center等属性),两边都会不爽。

    /*
    * @author zhoushengtao(周圣韬)
    * @since 2015年9月30日 凌晨 1:00:20
    * @weixin stchou_zst
    * @blog http://blog.csdn.net/yzzst
    * @交流学习QQ群:341989536
    * @私人QQ:445914891
    /
    这里写图片描述

    展开全文
  • React Native 三端(Web、iOS、Android)同构是指在不改动原 React Native 的代码下,让其在浏览器中运行出和在 React Native 环境下一样的页面。对于使用 React Native 开发的页面,如果又单独为 Web 平台重复写一...

    WeiboGoogle+用电子邮件发送本页面

    Comments

     

    0

    React Native 三端(Web、iOS、Android)同构是指在不改动原 React Native 的代码下,让其在浏览器中运行出和在 React Native 环境下一样的页面。对于使用 React Native 开发的页面,如果又单独为 Web 平台重复写一份代码代价是极其大的,而 React Native 三端同构能以零花费快速做到一份代码三端复用。

    React Native 三端同构的应用场景包括:

    • 在 React Native 页面崩溃时用对应的 Web 页兜底,以保证用户可以正常使用页面。
    • 对于需要分享到社交网络如微信朋友圈、微博的页面,不可避免地需要 Web 网页。

    React Native 三端同构基础原理

    React Native 就像一套新的浏览器标准,它提供了大量内置的原生 UI 元素和系统 API,对应着浏览器中的 div、img 等标签以及 BOM API;但是 React Native 目前只专注于移动 App 平台,只适配了 iOS 和 Android 两大系统,而浏览器则是适配了各种操作系统。由于 React Native 需要适配的平台更少所以性能会比浏览器要好。

    React Native 是基于 React 实现的,编写 React Native 应用和编写 Web 应用一样需要编写大量 React 组件。我们编写的 React 组件经过 render 后会以虚拟 DOM 的形式存储在内存中,React 只负责 UI 层面的抽象和组件的状态管理,各平台都可用虚拟 DOM 去渲染出不同的结果,React 架构如图 1 所示:

    图 1. React 架构

    点击查看大图

    由此可见,虚拟 DOM 这层中间抽象在实现 React 渲染到多端时发挥了很大的作用。

    ReactNative 三端同构方案对比

    目前社区中已经有多个 React Native 三端同构方案,比较成熟的有 reactxp 和 react-native-web,下面分别介绍这两种方案并从多方面对比二者以帮助你做出合适的选择。

    认识 reactxp

    reactxp 是一个跨平台的开源 UI 库,由微软 Skype 团队维护,Skype 产品中就大量使用了它来实现写一份代码运行在多个平台上。目前 reactxp 支持以下平台:

    • iOS/Android:基于 React Native 渲染。
    • Web:基于 react-dom 渲染。
    • UWP:基于 react-native-windows 渲染。
    • 其他平台 (如 Mac、Windows10 以下系统、Linux 桌面):基于 Web 渲染的 Electron 

    reactxp 实现原理

    reactxp 充份发挥了 React 虚拟 DOM 的优势,它其实只是充当胶水的作用,把各个平台的渲染引擎整合起来,对外暴露平台一致的接口,reactxp 架构如图 2 所示:

    图 2. reactxp 架构

    reactxp 为各个平台都实现了一份代码,在构建的过程中构建工具会自动选择平台相关的代码进行打包输出。

    reactxp 的优缺点

    优点

    1. 写一份代码就可实现多端渲染,对于有多端需求的产品可以减少代码量和人力。
    2. 由微软 Skype 团队维护并且用于 Skype 产品中,有大公司投入资源支持。
    3. 基于 TypeScript 编写,对 IDE 友好。

    缺点

    1. 为了抹平多端平台差异导致灵活性降低,暴露的组件和 API 较 react-native 要少很多。
    2. 需要兼容 UWP 平台导致包袱更重,而目前会针对 Windows 桌面或手机开发应用的产品在渐渐减少,大多数产品不需要支持 Windows 平台。
    3. 需要多导入 reactxp 这个库,导致打包输出的 bundle 会变大;并且由于多了一层适配,运行时性能肯定不如直接使用 React Native。

    其中最为致命的缺点可能在于目前 reactxp 支持的组件和 API 相当匮乏,一些比较细的操作无法控制。如果你的项目中确实有超出 reactxp 的能力范围的需求,可以通过导入和使用 React Native 实现,但这会导致整个项目脱离 reactxp 体系而无法实现多端同构。reactxp 只保证在它的体型内实现多端同构,但在其体系内却有很多 API 不可用。

    reactxp 和 React Native 的异同点

    从使用层面来说它们最大的区别在于:用 reactxp 写的一份代码可以在多个平台运行,而 React Native 是学会它后可多个平台编写原生应用但还得为不同平台编写不同代码。

    这一点从 reactxp 和 React Native 暴露出的 API 就可以看出来:React Native 中有大量诸如 SegmentedControlIOS、PermissionsAndroid 这样针对特定平台的 API,而 reactxp 中所有的 API 在所有端中都可以正常调用。

    事实上 React Native 也在为多端接口统一做努力,React Native 中的大多数接口是可以在多端运行一致的,但为了保证灵活性 React Native 也提供了平台相关的接口。而 reactxp 抹平了多端接口的差异,但这也导致 reactxp 灵活性降低。

    二者的相同点是都采用了 React 框架编程的思想,由于 reactxp 是基于 React Native 封装的导致两者大多数 API 的使用方式都是一致的。

    认识 react-native-web

    react-native-web 是由 Twitter 工程师 Nicolas Gallagher 实现并维护的开源项目,目前已用在 Twitter、Flipkart、Uber 等项目中,它支持把 React Native 编写的项目转换成 Web 应用。

    为 React Native 项目接入 react-native-web 成本极低:react-native-web 对原项目没有侵入性,无需改动原来的代码,只需在项目中加入一些 webpack 构建配置即可构建出运行出和 React Native 应用一致效果的 Web 应用。

    react-native-web 实现原理

    react-native-web 实现了在不修改 React Native 代码的情况下渲染在浏览器里的功能,其实现原理如下:

    在用 webpack 构建用于运行在浏览器里的代码时,会把 React Native 的导入路径替换为 react-native-web 的导入路径,在 react-native-web 内部则会以和 React Native 目录结构一致的方式实现了一致的 React Native 组件。在 react-native-web 组件的内部,则把 React Native 的 API 映射成了浏览器支持的 API。react-native-web 架构如图 3 所示:

    图 3. react-native-web 架构

    react-native-web 和 reactxp 异同点

    react-native-web 和 reactxp 的目的都是为了实现多端同构,但 react-native-web 只专注于 Web 平台的适配,而 reactxp 则还需要适配 UWP 平台。

    在实现 Web 平台的适配过程中它们都采用了类似的原理:把对外暴露的 API 或组件映射到 Web 平台去。但在实现 Web 平台的样式适配时二者有细微区别:

    • reactxp 全部通过内联样式实现。
    • react-native-web 通过为每条不同的样式生产一个 className,对于重复出现的样式则通过复用 className 实现。

    对于这两种不同的实现方式,我更看好 react-native-web 的实现方式,原因有两个:

    1. 通过复用 className 节省网络传输字节,如果你需要做服务端渲染这个优势会凸显出来。
    2. 通过 className 的方式浏览器渲染性能更好,因为浏览器有做样式计算缓存优化,有人专门写了性能对比测试页面

    表 1 列出了 reactxp 和 react-native-web 在其他方面的对比:

    表 1. react-native-web 和 reactxp 的对比

    对比项 reactxp react-native-web 对比结果
    维护人 微软 Skype 团队和 GitHub 社区 来自 Twitter 的个人Necolas 和 GitHub 社区 reactxp 小胜
    服务端渲染支持 官方没有明确要支持 完全支持 react-native-web 胜
    Web 端包大小 435KB 354.4KB react-native-web 胜
    写代码效率 针对 reactxp 暴露的 API 去实现多端适配 需要自己去验证代码在多端的表现是否一致 reactxp 胜
    学习成本 除了需要学习 reactxp 外,不可避免的还需要学习 React Native 只需学习 React Native 即可 react-native-web 胜
    Github 数据 start=2017 年 4 月 star=6521 issues=23/739 commits=814 start=2017 年 7 月 star=10151 issues=45/1034 commits=1248 react-native-web 用户更多,代码变动频率更大。reactxp 问题响应速度更快。

    如何选择

    如果你开发的产品有适配 UWP 平台的需求就选择 reactxp,否则选择 react-native-web,因为 reactxp 相比于 react-native-web 除了多支持 Windows 平台外,并无其它明显优势。

    reactxp 接入

    由于 reactxp 所有暴露的 API 都支持在 Web 平台和 React Native 平台同时正常运行,因此为 reactxp 应用转 Web 的方法非常简单,只需为项目加入 webpack 构建和运行 Web 页面的 index.html 文件。

    reactxp 的 webpack 配置文件如清单 1 所示:

    清单 1. reactxp 的 webpack 配置文件 webpack.config.js

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    module.exports = {

      entry: "./src/index.tsx",

      mode: "development",

      output: {

        filename: "bundle.js",

        path: __dirname + "/dist"

      },

      resolve: {

        // 优先加载 web.js 后缀的文件

        extensions: [".web.js", ".ts", ".tsx", ".js"]

      },

     

      module: {

        rules: [

             // 转换 TypeScript 文件   

          { test: /\.tsx?$/, loader: "awesome-typescript-loader" }

        ]

      }

    };

    再写一个运行 Web 页面的 index.html 文件,内容如清单 2 所示:

    清单 2. reactxp 平台启动入口文件 index.html

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    <!doctype html>

    <html>

    <head>

      <meta charset='utf-8'>

      <style>

        html, body, .app-container {

          width: 100%;

          height: 100%;

          padding: 0;

          border: none;

          margin: 0;

        }

        *:focus {

            outline: 0;

        }

      </style>

    </head>

    <body>

      <div class="app-container"></div>

      <script src="dist/bundle.js"></script>

    </body>

    </html>

    完整的例子可以参考 reactxp 的官方例子

    react-native-web 接入

    为了给你现有的 ReactNative 接入 react-native-web,实现 ReactNative 三端同构的能力,你需要做以下事情:

    1. 安装新的依赖,按照依赖的命令如下:

      # 运行时依赖

      npm i react react-dom react-native-web react-art

      # 构建工具

      npm i -D webpack webpack-dev-server webpack-cli babel-loader babel-plugin-transform-runtime

    2. 为 Web 平台写一份 webpack 配置文件 webpack.config.js,内容如清单 3 所示:

      清单 3. webpack 配置文件 webpack.config.js

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      module.exports = {

        module: {

          rules: [

            {

              // 支持图片等静态文件的加载

              test: /\.(gif|jpe?g|png|svg)$/,

              use: {

                loader: 'file-loader'

              }

            },

            {

              // React Native 包中有很多 es6 语法的 js,需要用 babel 转换后才能在浏览器中运行

              test: /\.js$/,

              use: {

                loader: 'babel-loader',

                options: {

                  cacheDirectory: false,

                  presets: ['react-native'],

                  plugins: [

                    // 支持 async/await 语法

                    'transform-runtime'

                  ]

                }

              }

            }

          ]

        },

        resolve: {

          // 优先加载以 web.js 结尾的针对 web 平台的文件

          extensions: {

              '.web.js',

              '.js',

              '.json',

          },

          alias: {

             // 把 react-native 包映射成 react-native-web

            'react-native$': 'react-native-web'

          }

        }

      }

    3. 写一个针对 Web 平台启动入口文件 index.web.js,内容如清单 4 所示:

      清单 4. Web 平台启动入口文件 index.web.js

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      import { AppRegistry } from 'react-native';

       

      // 注册组件

      AppRegistry.registerComponent('App', () => App);

       

      // 启动 App 组件

      AppRegistry.runApplication('App', {

        // 启动时传给 App 组件的属性

        initialProps: {},

        // 渲染 App 的 DOM 容器

        rootTag: document.getElementById('react-app')

      });

    4. 写一个 index.html 文件,引入 webpack 构建出的 JavaScript,以在 Web 平台运行,内容如清单 5 所示:

    清单 5. Web 平台启动入口文件 index.html

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    <html>

    <head>

        <meta charset="UTF-8">

        <meta name="viewport"

              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.

    0, minimum-scale=1.0">

        <meta http-equiv="X-UA-Compatible" content="ie=edge">

        <!--以下是正常运行所需的必须样式-->

        <style>

            html,body,#react-root{

                height: 100%;

            }

            #react-root{

                display:flex;

            }

        </style>

    </head>

    <body>

    <div id="react-root"></div>

    <script src="main.js"></script>

    </body>

    </html>

    完成以上步骤后重新执行 webpack 构建,再在浏览器中打开 index.html 你就可以看到 React Native 转出的 Web 网页了。

    完整的例子可以参考 react-native-web 的官方例子

    适配自定义的 Native Modules

    React Native 开发的 App 中经常会出现 React Native 官方提供的 Native Modules

    够用的情况,这时你会在项目中开发自己的 Native Modules,然后在 JavaScript 中去调用自己的 Native Modules。这在 ReactNative 环境下运行没有问题,但转成 Web 后执行时会报错说 Native Modules 上找不到对应的模块,这时因为在浏览器环境下是不存在这些自定义的 Native Modules。为了让页面能正常在浏览器中运行,需要为 Web 平台也实现一份自定义的 Native Modules,实现方法可以在 Web 平台的执行入口的最开头注入以下 polyfill,内容如清单 6 所示:

    清单 6. NativeModules polyfill.js

    1

    2

    3

    4

    import { NativeModules } from 'react-native';

    import MyModule from './MyModule'; // 实现自定义 Native Modules 的地方

     

    NativeModules.MyModule = MyModule; // 挂载 MyModule

    这段代码的作用是把针对 Web 平台编写的自定义原生模块挂载到 Native Modules 对象上成为其属性,以让 JavaScript 代码在访问自定义 Native Modules 时访问到针对 Web 平台编写模块。

    编写特定平台的代码

    为了让 React Native 三端同构能正常的运行,在有些情况下你不得不编写平台特定的代码,因为有些代码只能在特定平台下才能运行,编写特定的 Web 平台代码有以下三种方法:

    1. ReactNative.Platform.OS:所有端的代码都在一个文件中,通过以下代码来写 Web 平台专属代码:

      import { Platform } from 'react-native';

       

      if(Platform.OS==='web'){

        // web 平台专属代码

      }

    2. process.env.platform:通过 webpack 注入的环境变量来区分:

      if (process.env.platform === 'web') {

        // web 平台专属代码

      }

      这段代码只会在 Web 平台下被打包进去,这和 ReactNative.Platform 的区别是:后者的代码会打包进所有的平台。

      要使用这种方法需要你在 webpack.config.js 文件中注入环境变量:

      plugins: [

          new webpack.DefinePlugin({

              'process.env': {

                  platform: JSON.stringify(platform),

                  __DEV__: mode === 'development'

          }),

      ]

    3. .web.js: 在 Web 模式下会优先加载 .web.js 文件,当 .web.js 文件不存在时才使用 .js 文件。

    总结

    React Native 三端同构在理论上虽然可行,并且有现成的方案,但实践是还是会遇到一些问题,例如:

    • 在 Web 平台运行出的样式和 React Native 平台不一致,针对这种情况一般是 react-native-web 库的适配问题,可以在 Github 上提 issue 或 Pull Request。
    • 有些 React Native 提供的 API 在 Web 平台不可能实现适配,例如调摄像头、振动等,对于这种问题可以在 Web 平台裁剪掉这些功能或使用其他交互方式替代。

    React Native 三端同构虽然无法实现 100% 和 React Native 环境运行一致,但能快速简单的转换大多数场景,以低成本的方式为你的项目带来收益。

    参考资源

    原文https://www.ibm.com/developerworks/cn/web/wa-universal-react-native/index.html?ca=drs-&utm_source=tuicool&utm_medium=referral

    展开全文
  • React Native 复习生命周期 关于React Native,我知道的不多
  • 前言React Native 是最近非常火的一个话题,因为它的语法简介,跨平台等特性,赢得了各大平台的青睐,虽然前期是有一些坑。基本概念解释React 是一套可以用简洁的语法高效绘制 DOM 的框架,所谓的“高效”,是因为 ...
  • 在浏览器中我们可以通过&lt;a&gt;标签与url实现不同页面之间的跳转,利用浏览器的...React Navigation就是这样一个源于ReactNative社区的用于实现界面导航的js库。通过如下方法安装react navigation到你的...
  • react native实现登录...demo下载:react-native 完整实现登录功能1.完整目录2.实现的界面3.主界面的代码实现import React, { Component } from 'react'; import { ToolbarAndroid, AppRegistry, StyleSheet, Tex
  • 完全征服React Native

    2018-10-22 21:38:05
    React Native是Facebook于2015年推出的跨平台开发...本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合
  • (一)前言 前几节课程我们对于React Native的一些基础配置,开发工具以及调试,Android项目移植做了相关讲解,今天一起来学习一下另外一个比较重要的知识点,就是React Native项目签名打包。 刚创建的React Native...
  • (一)前言 现在几讲我们对于React Native一些基础做了相关讲解(例如:环境搭建,开发IDE,调试以及升级降级等),今天开始正式进入UI相关组件学习的阶段了。首先我们来讲一个非常基础的组件View。 刚创建的React Native...
  • 最近做了两个React Native(以后简称RN)的项目,重新Review一下相关的项目代码,期望下次使用的时候可以有更好的结构,更好的规范和约束已帮助大家减少bug,提高开发效率; ​ 在做了一些原生Android开发,iOS开发和基于...
  • 来自俄罗斯新西伯利亚的开发者Dima日前在GitHub上开源了一款名为React Native Desktop的开发利器,可以让开发者使用React Native构建OS X桌面应用程序,并分享了自己研发所得的示例,项目截至目前已经收获了五千多...
  • 首先我们要有个概念:react native里面是兼容大部分我们在css里面用到的布局方式,此外接触过css里面flex布局方式的话,我们会发现react native内的flex布局方式基本上和css里的flex布局方式类似,所以不要觉得react...
  • 1 前言最近打算真的开始学习一下跨平台APP开发,一直在关注RN,因此也打算真的开始学习下(其实是笔者的公司也开始有这种跨平台的需求了,笔者在一家传统公司)。...需要的开发环境主要有node.js + react native +
  • 由于其他的原因,对于React Native相关的内容最近没有投入太多的关注,从去年年底出版了《React Native移动开发实战》后,对于React Native的关注就比较少了。最近由于公司之前的项目需要,所以React Native又重新...
  • 摘要 2015年是React Native发展的一年,2016年必定是React Native蓬勃的一年!2016年React Native很可能成为最为成功的开源技术之一。为什么React Native这么火呢?那么React Native相比H5、Native又有哪些优势呢?...
  • 欢迎大家关注【跨平台开发那些事】公众号,定期推...基于最新版本React Native实现JsBundle预加载,界面秒开优化 一、开源库介绍 今年1月份,新开源的react-natvigation库备受瞩目。在短短不到3个月的时间,gith...
1 2 3 4 5 ... 20
收藏数 59,814
精华内容 23,925
关键字:

reactnative