ピアッザアプリ大幅アップデートのハマりポイント
この記事は React Native Advent Calendar 2020 の 19 日目の記事です。
はじめに
PIAZZA 株式会社でエンジニアをしている奥澤です。 2016 年 10 月に React Native で開発した Android 版 ピアッザ をリリースしました。
2017 年より、ReactNative の Advent Calendar に参加させて頂いております。
毎年、1 年の振り返りをまとめていたのですが、今回は 12/14 にリリースした大型アップデートで苦労した点を中心に共有したいと思います。
前提条件として
- 開発ターゲットは Android のみ
- React 16.8.6
- React Native 0.59.9
という環境での Tips なので直接役に立つケースは少ないと思いますが、何かのヒントになれば幸いです。 ちなみに、変更箇所は追加/削除合わせて 1 万行超、変更ファイル数は 212 でした。
ピアッザ最新版 v4.0 について
今まではユーザーが閲覧するエリアを都度切り替えると、アプリ全体がそのエリアの情報のみを表示する、ある意味閉じた環境でしたが、v4.0 ではいわゆるニュースアプリのような UI になり、トップタブでエリアを横断した情報が閲覧でき、タブによって複数のエリアの切り替えがスムーズにできるようになりました。
この UI を実現するにあたり、前提条件の中でハマった点が以下になります。
react-native-scrollable-tabview
タブの表示には、 react-native-scrollab-tabview を使っています。今回のアップデート以前から他の画面にで利用させてもらってますが、ニュースアプリ風 UI を実現する上で、2 箇所ハマりポイントがありました。
タブの並び替えによって参照先が変わると反映されない
react-native-scrollable-tabview では内部で tabLabel によって viepager の参照先を管理していますが、tabLabel が動的に変わっても、参照先はかわりません。なので初回描画時の参照先をずっと参照しつづけるため、タブの並び替えの対応ができません。
今回は、闇に葬られていたこちらの PR を使わせて頂きました。(ローカルでこちらの commit の patch を作って対応)
タブのラベル名を変更後に、タブ全体のサイズが更新されない
タブのラベルに各エリアの新着投稿件数を(1)みたいに表示していて、タブを開くときに新着数を消すと、タブ全体の width が更新されないため、隙間ができたり逆に新着投稿数を後から追加すると初期化時の width より大きくなりタブが表示されなかったりします。 こちらも、↑ の patch によってサイズの再計算が走ることにより解決できました。
課題: タブ全体更新時のパフォーマンス
タブの削除・並び替え時に、前述の patch を当てた react-native-scrollable-tabview によって更新が走るのですが、更新が終わるまで少し待たされる感じになります。ここは時間がなくてチューニングしきれず…
タブの並び替えの実現
最初は依存ライブラリが少ない react-native-draggable-dynamic-flatlist で実装したのですが、どうにもパフォーマンスが悪く納得できる挙動でなかったため、リリース直前に react-native-draggable-flatlist に乗り換えました。ただ、前提条件にあるように、ReactNative 0.59.9 利用のため導入にかなり苦労しました…
結論から先に書くと今回導入した各ライブラリの version は
"react-native-draggable-flatlist": "^2.5.1",
"react-native-gesture-handler": "^1.3.0",
"react-native-reanimated": "^1.2.0",
です。
各ライブラリ導入時のハマりポイント
- https://majintools.com/2019/08/06/dexfile/
- https://github.com/computerjazz/react-native-draggable-flatlist/issues/100
- https://github.com/computerjazz/react-native-draggable-flatlist/issues/161
今回、本来は Modal 内で react-native-draggable-flatlist を使いたかったのですが、最新版を入れる事ができないため断念しました。最新版でなくても、0.60 以降でないととにかく今は厳しいですね…
パフォーマンス
タブを切り替えにより各エリアのタイムラインが表示されるのですが、初回実装時はタブを切り替える毎に 10 数秒(しかも開いたタブが増える事に時間が長くなる…)という極めて動作が重い状態でした。こちら原因突き止めるのに 3 日間かかったのですが理由としては、React/Redux/Immutable.js をきちんと理解していなかった事が原因です。4 年半使ってるのに情けない。。。
詳細は、各 Screen の mapStateToProps (これも早く hook 化したい) で
{
article: state.article.toJS()
}
みたいに横着していたせいです。今までのアプリではこれでも問題ありませんでしたが、今回の実装では、例えばあるエリアのタブが ↑ のように article を参照してる状態で、他のエリアタブで article を fetch すると全てのタブで更新が走ってしまいます。なので、タブを開く度に激重になるという顛末でした。。まあ、自分が悪いんですが、このあたり気にしなくてもパフォーマンス問題ないような React/ReactNative/Redux になっていってほしいな…という気持ちもあります。
↑ の toJS() 抹殺の他に、useMemo, useCallBack も積極的に利用することにより、最終的にはそこそこ納得の行くパフォーマンスとなりました。
その他
react-native-image-croppicker
各種ライブラリを入れ直してるときに、うっかり最新版をいれたらエラーに
https://github.com/ivpusic/react-native-image-crop-picker/issues/1304#issuecomment-639246786
まとめ
React Native 0.60 以降に早くアップデートせねば!!!!!
最後に
↑の募集はサーバーサイドですが、私と一緒に ReactNative で Android アプリを開発して頂ける方も、めっちゃ募集中です!!!
一人で作るのは、さすがに限界になってきたので切実です。。。
React Native Advent Calendar 2020 20日目は @eishis さんです!