さかなソフトブログ

プログラミングやソフトウェア開発に関する情報

プログラミング

react-nativeをv0.55.4からv0.57.8にアップグレードする

投稿日:

React Nativeの最近のバージョンアップはマイナーバージョンが以前は毎月だったものが約3ヶ月毎にリリース期間が長くなっており、その間、1ヶ月に数回のペースでパッチバージョンがリリースされ、今まで致命的なバグが放置されてきたものが漸く解消されてきました。

現在従事しているプロジェクトではv0.55.4までアップグレードしたところで、バグが解消されないのでアップグレード出来てませんでしたが、v0.56でReact Nativeの内部が再構築され、v0.57で多くの問題が解消していると判断したのでそろそろ良いタイミングだということでアップグレードすることにしました。

スポンサーリンク

正方形336

v0.55からv0.57で加わった大きな変化

Babel7にアップデート

正確にはReact Native v0.56で加わった変更で、Babelが7にメジャーアップしました。React Nativeとして主な影響はBabelモジュールを@babelスコープに変更したこと、JSプリセットがes2015のような年号プリセットが廃止されています。

安定性の向上

v0.55.4では(特にAndroidでの)ネットワーク関連、日本語入力関連で致命的なバグがあり苦しい回避策を講じる必要がありましたがv0.57.8では解消しています。詳細については後述します。

アップグレード手順

公式ドキュメントでアップグレード手順を把握

Upgrading to new React Native versionsに基本的な手順が、react-native-releases/CHANGELOG.mdにバージョン別の変更履歴とアップグレードの注意が書いてあるので読んでおきます。

react-native upgradeにてアップグレード

既存ソース部分のアップグレードはNativeモジュールを利用しているReact Nativeプロジェクトの場合はreact-native-git-upgradereact-native upgradeの2通りの方法があります。

公式で推奨するのはreact-native-git-upgradeの方で、package.jsonのバージョン更新まで自動で行ってくれるので便利なのですが、今回適用しようとしたプロジェクトではpackege.jsonやNative側のソースでかなり手を加えていたからか、実行時に競合が発生してエラーで終了してしまい利用出来ませんでしたのでreact-native upgradeの方法を利用しました。手順は以下の様になります:

  1. package.jsonのreact-native0.57.8に、react及びreact-test-renderer16.6.3に変更
  2. $ yarn
  3. $ react-native upgrade
    • 競合が大量に出てファイル毎に取り扱い方法を対話形式に出るのでとりあえず.gitignore以外は全部上書きしてなにが書き換わるか確認する
  4. ic_launcher.png等のアイコン系ファイルは追加すると公式アイコンを消してしまうので全て削除する
  5. 他の差分はappで独自に追加したモジュール類が上書きで削除されているので元に戻す
    • 根気の要る作業なので数時間かける覚悟を持ってやる
  6. $ react-native run-ios(android)

これで一応、アプリが立ち上がるようになりました。この時点では複数のwarningと、機能によっては動作しない部分がありますので詳細は1つづつ紹介していきます。

Nativeソースを自分で書き換えたソース部分に関しては上手くマージすることが出来ず、iOSのproj内コードまでも競合して手動で変更せざるを得なかったところが非常に苦労しました。この辺はアップグレードの度に毎回作業を強いられるととても辛いのでReact Native側に頑張って貰いたいところです。

実行してみて躓いたところとその対応方法

HtmlViewモジュールで Failed prop type: Invalid prop 警告

react-native-html-viewを利用している画面を参照すると以下の様な不正prop type警告が発生しました:

warning: Failed prop type: Invalid prop
`RootComponent` of type `object` supplied to
`HtmlView`, expected `function`.
  in HtmlView (at PresentIndexScreen.js:107)

Fix error on react native version 0.56 caused by defaultProps for RootComponent by alphasp · Pull Request #228 · jsdf/react-native-htmlviewを参照すると、react-native-html-view v0.13.0で解消しているのでアップグレードします。

Animated: 'useNativeDriver' is not supported 警告

app起動時にAnimated: 'useNativeDriver' is not supported警告が発生しました:

Animated: `useNativeDriver` is not supported
because the native animated module is missing.
Falling back to JS-based animation. To resolve this,
add `RCTAnimation` module to this app, or remove
`useNativeDriver`. More info: https://github.com/
facebook/react-native/issues/11094#issuecomment-263240420

Button component generate warning · Issue #11094 · facebook/react-nativeを参考にするとlibRCTAnimation.aが正しく読み込めて無かったのでXCodeでモジュールを再追加しました。

react-navigationで画面遷移すると循環参照警告

画面遷移するとreact-native-safe-area-viewで以下の様な循環参照エラーが出ました:

Require cycle: node_modules/react-native-safe-area-
view/index.js -> node_modules/react-native-safe-
area-view/withSafeArea.js -> node_modules/react-
native-safe-area-view/index.js

react-navigation v2.12.1ではreact-native-safe-area-view v0.9.0に依存しており、このバージョンだと内部で循環参照が発生していました:
Require cycle in withSafeArea.js line 4 · Issue #40 · react-native-community/react-native-safe-area-view

react-navigation v2.12.1→v2.18.3にアップデートすることでreact-native-safe-area-view v0.9.0→v0.11.0にアップデートされ、循環参照警告が解消されました。

iOSで日本語入力が出来ない

react-native v0.55.4 iOSではTextInputで日本語入力が出来ない致命的なバグが有り、それを回避する為の対策コードを実装していました。

Controlled TextInput broken for Chinese (and other languages) in v0.54 on iOS · Issue #18403 · facebook/react-native

コメント内にいくつか回避策がありますが、これを適用した状態で v0.57.8にアップグレードすると逆に日本語が打てなくなる場合があるので回避コードを削除します。

TextInput.clear()サポートに伴う暫定対応解除

TextInputの入力をリセットするTextInput.clear()メソッドがv0.55.4では効かなかったのでユーザーが入力した文字列をリセットする際は一旦仮想DOMから外してre-renderして解除していました:

[0.54] TextInput.setNativeProps({text: ''}) no longer works · Issue #18272 · facebook/react-native

こちらはv0.57でサポートされたので入力テキストを消す部分の暫定対応を解除しました。以下は独自で定義した内部で使っているTextInputをonRefでオブジェクトを返すTextFieldコンポーネントで、入力確定するとonSubmitが呼ばれるように実装していた場合に入力テキストを消してフォーカスを外す様にした例です:

<TextField
   onSubmit={text => {
    this.textInput.clear();
    this.textInput.blur();
  }}
  onRef={ref => (this.textInput = ref)}
/>

Gifアニメーションしない

ImageコンポーネントでGifアニメーションを利用するために標準で組み込まれているfresco:animated-gifを利用していましたがv0.57.8のAndroidで表示はされるがアニメーションしなくなりました。

Issue with compile 'com.facebook.fresco:animated-gif:1.8.1' · Issue #18866 · facebook/react-nativeのコメントによると、RN Versionによってcom.facebook.fresco:animated-gifのバージョンが変わるとのこと。

RN Version Fresco Version
<= 0.55 <1.3.0
0.56 1.9.0
0.57 1.10.0

android/app/build.gradleanimated-gifバージョンを1.10.0にアップデートすることでアニメーションするようになりました:

implementation "com.facebook.fresco:animated-gif:1.10.0"

以前のバージョンではcom.facebook.fresco:animated-base-support:1.3.0がありましたが新しいバージョンが無くなっています。これはAndroid 4.0より以前のバージョンをサポートしたい場合に組み込むようでしたが、既にターゲットバージョンから外していたのでこのタイミングで削除しました。

babel-preset-react-nativeモジュールの廃止

react-native-releases/CHANGELOG.md at master · react-native-community/react-native-releasesより、v0.56 → v0.57 でJS presetがbabel-preset-react-nativeからmetro-react-native-babel-presetに変更しました:

{
  "presets": ["module:metro-react-native-babel-preset"]
}

それに伴い、metro-react-native-babel-presetはreact-nativeに標準で依存しているのでなにも新しくインストールする必要は無いのですが、babel-preset-react-nativeは利用することが無くなったので古いモジュールをpackage.jsonより削除しました。

NetInfo.isConnected.fetch()を複数同時リクエストするとレスポンスが返ってこない

RN0.55.4だと、API呼び出しなどでfetch()を呼び出した際、オフラインなどの理由で失敗するとAndroidでクラッシュするという致命的なバグがありました。

そのため、オフライン時には呼び出しを発生させないように事前にNetInfo.isConnected.fetch()で現在のネット接続状況を確認してからfetch()を呼び出していました。

Android crash when network changes from Good to Bad · Issue #10423 · facebook/react-native

それが今度はRN0.57.8ではiOSでNetInfo.isConnected.fetch()を起動時は複数のAPIを呼び出し必要があって複数同時リクエストしたら1つ以外のresolveが返ってこないという別の致命的なバグが発生してしまいました...

Multiple fetch request starts to not resolve or reject promise · Issue #21862 · facebook/react-native

2019/01/25現在でもこのIssueはOpenでまだ直って無い様ですが、fetch()の方はv0.57.8にアップグレードすることでオフライン時でもクラッシュせずにエラーで返ってくるようになったのでNetInfo.isConnected.fetch()の事前チェックを廃止することでこの問題を回避してAPI呼び出しを行う事が出来る様になりました。

まとめ

まだ不安定な部分もあるんですが、最近のメジャーバージョンアップは少しづつ致命的なバグが取り除かれてきており、枯れたフレームワークへのスタートラインに立ちつつあります。

そうこうしているしている間に先日React Native v0.58.1がリリースされましたが、まだ情報も殆ど無く、えいや、とアップグレードする勇気は無いのでバグFIXがある程度入ったパッチバージョンがインクリメントされたあたりでこちらも試してレポートしたいと思います。

正方形336

正方形336

-プログラミング
-,

Copyright© さかなソフトブログ , 2019 All Rights Reserved.