美文网首页前端
前端和RN代码互转总结

前端和RN代码互转总结

作者: 点燃火焰 | 来源:发表于2018-03-02 13:48 被阅读995次

    React Native出现的目的本就是“learn once, write anywhere”,Facebook希望人们能够学习一次,到处使用,但是同样是JS代码,从前端移植到RN,或者RN移植到前端,却并没有想象的那么容易。事实上除了语法相同外,还有很多不一样的地方,导致我们没法做到直接copy,以下是我在做迁移代码的时候,总结的一些经验

    1 Antd Mobile

    Antd Mobile的蚂蚁金服开源的一套UI组件,已经实现了前端、iOS、Android的三端统一UI,推荐大家多多使用

    1.1 Flex

    1.1.1 使用Flex的参数

    多用direction justify align 属性,因为某些移动端浏览器不支持Flex功能,影响到适配,而antd已经帮我做过了,只是需要我们采用以下写法,否则无效
    例如:
    Good:
    <Flex direction="column" align="start" justify="startt">

    Bad:(这种写法并没有利用到Flex本身的适配)

    <Flex style={{  
    flexDirection: "column",  
    backgroundColor: "white",
    justifyContent: "flex-start"
    }}>
    

    这样的话,因为前端的兼容性你需要写很多适配的css代码,例如

    {
          display: flex;
          display: -webkit-flex;
          flex-direction: row;
          -webkit-flex-direction: row;
          justify-content: flex-start;
          -webkit-justify-content: flex-start;
          align-items: center;
          -webkit-align-items: center;
    }
    

    1.1.2 显示指定flexDirection

    因为某些情况下Flex无法使用,例如RN端的Touchable组件只能包裹原生组件,必须用View替代Flex,而View和Flex的默认方向是不一样的,因此显示写出flexDirection,明确告知方向,方便迁移者改动代码
    Good:

    <Flex  direction="column">
         {...}
    </Flex>
    

    Bad:(替换成View时候方向会错)

    <Flex>
         {...}
    </Flex>
    

    1.2 ListView

    在RN 0.51版本下,antd的ListView会报错,还是使用RN提供的ListView,只需要修改import ListView即可,其他写法完全一致

    // 不推荐
    import { ListView } from "antd-mobile";
    // 推荐
    import { ListView } from "react-native";
    

    2 代码规范

    2.1 尽量组件化

    某些页面很复杂,常见的一种写法是将页面拆分成若干模块,每个模块写一个moduleRender函数,再在render函数里分别调用,类似以下

    Bad:

    class SomeComponent extends Component {
          renderSubOne() {
            return <Flex>{...}</Flex>;
          }
          renderSubTwo() {
            return <Flex>{...}</Flex>;
          }
          renderSubThree() {
            return <Flex>{...}</Flex>;
          }
          render() {
             return <Flex>
                {this.renderSubOne()}
                {this.renderSubTwo()}
                {this.renderSubThree()}
              </Flex>
          }
    }
    

    Good:

    1. 因为迁移很可能是迁移某一部分,尽量拆分成组件迁移起来更灵活
    2. 这种写法性能更高,分开写的话每个组件有自己的生命周期,某个子组件刷新时不会影响父组件
    class SomeComponent extends Component {
          render() {
             return <Flex>
                <SubOne />
                <SubTwo />
                <SubThree />
              </Flex>
          }
    }
    

    2.2 不要用css

    关于样式的写法,RN和前端有个显著的差别
    RN:

    import { StyleSheet } from "react-native";
    
    const styles = StyleSheet.create({
     someContainer: {
        fontSize:16,
        fontWeight: 'bold',
      },
      ...
    })
    
    <Flex style={styles.container} />
    

    前端:

    // js 文件
    import CSSModules from 'react-css-modules';
    ...
    
    @CSSModules(styles)
    ...
    
    <Flex className="someContainer">
    
    // css文件
    .someContainer{
          font-size: 16px;
          font-weight: bold;
     }
    

    由上面示例可知

    1. 前端的样式是藏在css文件内的,迁移起来需要一一去查找
    2. 关键字命名不同(font-size,fontSize)

    而这些不同都需要我们迁移的时候一一手动修改,工作量很大

    推荐的写法,是统一使用RN的写法:

    // 前端js文件
    const styles = { // 这里不需要像RN一样,使用StyleSheet.create
     someContainer: {
        fontSize:16,
        fontWeight: 'bold',
      },
      ...
    }
    
    <div style={styles.container} />
    

    2.3 第三方组件

    挑选第三方组件要注意

    1. 尽量使用原生,或者antd
    2. 尽量选择支持前端和移动端的
    3. 尽量选择有人维护的
    4. 如果git无人维护或者年代久远,建议将代码copy过来,而不是用npm管理,因为RN和React版本更新的原因,常常需要手动修改部分代码,才能运行,因此直接copy至工程里,比较方便

    3 差异

    有一些差异是前端和RN天然的差异,需要注意

    3.1 Image

    加载图片资源在两端写法并不一样,需要手动修改
    前端:

    <img style={{ width: 98, height: 82 }} src={nullImg} alt="nullImg" />
    

    RN:

    <Image style={{ height: 15, width: 15, marginLeft: 10 }} source={{ uri: 'search3' }} />
    

    3.1.1 RN的Image

    需要特别注意一下的是,React Native 0.50.3以后,Image不再能包裹child

    <Image> // 0.50.3以后,这种写法报错
          {...child...}
    </Image>
    

    3.2 Text文本

    前端渲染文本有多种标签,<div>,<span>等,但是RN端只有一种<Text>,这在迁移时会带来很大的工作量,文本散落在各个地方,需要人工一一替换。
    推荐使用react-intl,这个有Yahoo提供的第三方组件,实现了在前端、RN端的统一

      <FormattedMessage
        style={styles.valueDesc}
        id="someId"
        defaultMessage={text}
      />
    

    3.3 响应事件

    前端:

    // 可以添加在任何标签上
    <div onclick={()=>{}} />
    <img onclick={()=>{}} />
    

    RN:

    <TouchableHighlight onPress={}>// 只能有一个子元素,且必须是RN原生组件,不能是自定义组件
      <View> // 要用一个View来包裹更多的元素
          {child}
      </View
    </TouchableHighlight>
    

    由上可知,点击事件迁移时,常常需要改动较多的代码

    1. 增加TouchableHighlight标签
    2. 原标签下,如果有多个子标签,那么还需要增加View来嵌套,还要注意样式保持不变
    3. onClick改成onPress

    3.4 路由跳转

    • 前端使用react-route
    • RN端根据具体情况会有不同选择,例如react-navigationreact-native-navigation

    写法上会有不同,需要迁移者根据具体选择的库,手动修改

    3.5 PropTypes

    PropTypes是React提供的一种类型检测工具,但是随着版本的变迁,从React v15.5起,PropTypes被移出了React,形成了一个单独的库,如果前端和RN两边版本不一致,还有可能需要人工大量修改

    // react version < 15.5
    import React, { Component, PropTypes } from 'react';
    
    // react version >= 15.5
    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    

    3.6 全局变量

    前端js代码的运行环境通常是浏览器,浏览器本身提供全局变量window,而RN端则没有,因此不要在前端使用window全局变量,而是要使用导入文件

    Bad:

    window.someVar = var
    

    Good:

    // 新建constants.js文件
    const object = {
       website:'http://www.hao123.com',
       name:'好123',
    };
    export default object;
    
    // 需要使用时导入
    import constants from './constansts.js'
    <Text>{constants.name}</Text>
    

    相关文章

      网友评论

        本文标题:前端和RN代码互转总结

        本文链接:https://www.haomeiwen.com/subject/xmcnxftx.html