美文网首页
RN 升级纪要(0.52->0.59.10)

RN 升级纪要(0.52->0.59.10)

作者: jetzhliu | 来源:发表于2019-06-27 14:13 被阅读0次

    TL;DR

    升级RN可以带来以下好处:

    1. Hot Reloading 支持函数组件(旧版只支持 extends Component 方式);
    2. React 版本升级到16.8.6,可以使用 hooks 等新 API;
    3. 自带支持 Typescript,只要用 .ts.tsx 后缀即可,无需改任何配置,与现有 js 文件可共存。

    升级到 0.59 版本比 0.60 痛楚要小很多,只需要更改 App 构建配置以及部分原生组件的写法即可。

    升级背景

    事情的起因是谷歌宣布19年8月1号开始在Google Play上架的应用都必须支持64位体系,而RN版本对64位的支持从0.58才开始,而项目组使用的版本比这低,因此升级是在所难免的。考虑到升级后框架更稳定而且含有更多特性,事不宜迟马上开搞。

    升级的第一个问题是该升到哪个版本。当前时间段最新的版本有0.59和0.60(吐槽下时隔四年RN还没1.0版本)。从0.60的 changelog 中我们发现有一个重大的 breaking change 就是 AndroidX support。这个改动不像支持64位体系那样改改编译参数就行,还必须改动原生代码,是个改动量非常大的升级(主要是针对第三方库以及项目中的原生代码改动较大),而特性并没有比 0.59 多太多,反而去掉了很多以前的内置组件,移到社区托管了。因此最终钦定 0.59.10 为升级目标版本。

    对于用户以及开发人员而言,以下几点改动是比较明显的,即使不需要上架 Google Play 也可以参考一下以确定是否需要升级:

    1. Hot Reloading 支持函数组件(旧版只支持 extends Component 方式);
    2. React 版本升级到16.8.6,可以使用 hooks 等新 API;
    3. 自带支持 Typescript,只要用 .ts.tsx 后缀即可,无需改任何配置。

    升级iOS

    新版移除了 iOS 8.x 的支持,需要升级系统最低版本。另外,glog 依赖的名称变了。使用 Podfile的需要改动以下内容

    -platform :ios, '8.0'
    +platform :ios, '9.0'
    -    pod 'GLog', :podspec => '../node_modules/react-native/third-party-podspecs/GLog.podspec'
    +    pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
    

    新版的输入框组件(TextInput)类继承体系改了,若做了相关扩展需要同步修改

    原生封装的组件改动可能较多,需要多进行测试(自定义以及第三方原生扩展)。

    升级Android

    升级RN依赖后 appcompat-v7 会使用 28.0.0 版本,和项目中已使用的版本冲突,可使用以下方式降级处理。

    build.gradle

    allprojects {
        configurations.all {
            resolutionStrategy {
                force "com.android.support:appcompat-v7:26.0.1"
                force "com.android.support:support-v4:26.0.1"
            }
        }
    }
    

    RN 原生扩展组件很多时候是依赖于具体 RN 版本的,需要到各自官网查看升级描述。

    升级React

    使用 babel 插件转换旧代码

    由于 React 需要同步升级,而新版由于引入 fiber 渲染,原先的三个生命周期变得不再安全而计划废弃并且改了名字,需要进行替换。

    • componentWillMount
    • componentWillReceiveProps
    • componentWillUpdate

    由于尚有部分第三方库未升级,不方便在项目中修改,故引入 babel 插件精心统一替换。需添加react-rename-unsafe-lifecycle插件;若需要使用装饰器语法(如搭配redux或mobx),需要添加@babel/plugin-proposal-decorators插件。

    babel.config.js

    module.exports = {
      presets: ['module:metro-react-native-babel-preset'],
      plugins: [
        'react-rename-unsafe-lifecycle',
        '@babel/plugin-proposal-decorators', { legacy: true }
      ]
    };
    

    package.json

    {
      "dependencies": {
        "@babel/core": "^7.4.5",
        "@babel/runtime": "^7.4.5",
        "react": "16.8.6",
        "react-native": "0.59.10",
        "babel-plugin-react-rename-unsafe-lifecycle": "^1.0.4",
        "metro-react-native-babel-preset": "^0.54.1"
      }
    }
    

    虽然使用以上插件可以暂时运行,但在特殊场景下是不安全的,并且后续会废弃掉,因此后续应该持续跟进,把这些接口用新接口重写。

    官方迁移说明

    改写 componentWillMount()

    • 用于发起网络请求的移动到 componentDidMount()
    • 根据传入的 props 计算组件属性(this.xxx)的(同步),视情况移动到 constructor

    改写 componentWillReceiveProps()

    根据使用场景不同,按如下方式替换

    • 需要根据传入的 props 执行副作用,改用 componentDidUpdate()(注意state改变也会执行 componentDidUpdate,需多加判断)
    • 需要根据传入的 props 计算新state,参考 这里(比较少见)

    改写 componentWillUpdate()

    相关代码移动到 componentDidUpdate()shouldComponentUpdate()

    React Native (js)

    官方移除组件

    由于升级后 RN 官方仓库进行过瘦身,很多基本功能都移到社区维护了,用到了的需要手动添加回来。大部分组件规划在 0.60 正式移除,0.59 还能继续用,可考虑下次升级再处理。

    RN 移除的组件

    准备废弃的组件列表

    • ImageStore
    • ListView
    • MaskedViewIOS
    • Slider
    • SwipeableListView
    • ViewPagerAndroid
    • WebView
    • AlertIOS
    • AsyncStorage
    • NetInfo

    非公开接口

    有部分接口旧版本是没有公开的,需要用的只能根据路径引用。新版对路径进行了调整,导致引用报错。以下接口在新版做了改动,但已通过公开接口暴露出来,可以直接 import { XXX } from "react-native" 使用。

    • ColorPropType
    • EdgeInsetsPropType
    • PointPropType
    • ViewPropTypes

    行为变化的组件

    这部分改动最麻烦,只能发现一个改一个。目前发现以下问题:

    • FlatList 初始化时不会调用 onEndReached
    • ScrollView 的 scrollTo 方法 y 坐标不支持负值,scrollTo({y: -100}) 和 scrollTo({y: -0}) 效果一样
    • WebView 的 onMessage 接收到的数据会被 encodeURIComponent 两次,可以通过添加 useWebKit 属性解决,恢复旧版行为
    • react-native-webview 是从 RN 核心中抽离的 webview 组件,webview 发送消息需要用 window.ReactNativeWebView.postMessage 方法,和旧版的 window.postMessage 方式差异太大,不兼容线上代码,暂不考虑
    • NativeModules 改成了只读,需要修改只能复制一份修改然后替换整个 NativeModules
    • 原生封装的UI组件导出的常量使用方式改变,例如原来是通过 UIManager.RCTWebView.Commands.goForward 访问,现在需要使用 UIManager.getViewManagerConfig('RCTWebView').Commands.goForward

    整个升级流程下来还是挺顺畅的,处理原生的构建花了一点时间,后续 js 部分的修改很多时候只要看控制台报错就可以,提示还是很清晰的。

    App能跑起来后,基本功能没太大问题,但某些小角落可能会出现一些交互异常甚至奔溃,主要都是因为组件的 API 或者行为改变引起,需要做好充分的回归测试。

    相关文章

      网友评论

          本文标题:RN 升级纪要(0.52->0.59.10)

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