この記事は「React Native Advent Calendar 2020」の12日目の記事です。(忙しくて当日夜になってしまいました、すいません)
自己紹介
バックエンドのエンジニアとしてそろそろ8年になります。
元々、C#, Java, PHPなどでサーバーアプリケーションの構築に関わっていましたが、
最近になり、アプリ開発を行う機会も何度かありました。その中で ReactNative 開発案件に
2度ぶつかり、その中で「これが分かってたら、もうちょっとうまく開発できていたんじゃないか?」
と思うことがあり、これから ReactNative でアプリ開発を行う人向けに情報記載していきます。
なぜ ReactNative にエンカウントするのか...
ReactNative に関わる場合というのは、自分は大きく下記のパターンかと思っています。
- JavaScript(Vue.js等)でフロント開発をやっていた
- Reactでフロント開発をやってた
- Android/iOSでアプリ作っていた
自分は、「Android/iOSでアプリ作っていた」でした。
なお、自分の周りでは大半が「JavaScript(Vue.js/jQuery等)でフロント開発をやっていた」でした。
しかし、ReactNative で安定して開発するためには下記の知識が必要だと思っています。
- React 知識
- コンポーネント設計
- React native パッケージ
- iOS/Androidアプリ構築に関する知識
それぞれ、どんなことを抑えていればいいかという所感を記載します。
React 知識
自分は React をよく知らないまま、開発に入りました。
なんかよくわからないけど、React.Component
を継承してコンポーネント作っていけばいいんだな!
そこまでは既存コードを見れば、何となく分かりました。で Props と State が変化すれば画面も切り替わっていく。
しかし、思った通りのタイミングで描画ができません。
render メソッドが呼ばれないタイミングもあれば、逆に呼ばれまくって処理が重くなったり。
そのときの私は、ライフサイクルを理解していませんでした。
React component ライフサイクル図
(一部メソッドが廃止になってます: React.js のライフサイクルメソッド componentWillReceiveProps の廃止対応)
描画の問題はなんとかなりました。しかし、今度は画面間のデータ連携が上手くいかなくなります。
前の画面で入力されたデータを次のページに連携することは可能です。react-navigation を使ってパラメータを渡せば。
rearct native react-navigation 個人的メモ
しかし、2つ前の画面で設定されたデータを画面で表示するにはどうすればいいんだ..ということになり、
どこかにグローバル変数的にデータを持たせておき、参照するようにしました。
しかし、その定数を別画面が変更しても、Component 内のデータが変わっていないため、描画に変更が走りません。
どうすればいいんだー...と探し回り、出会ったのが、Redux でした。
Redux入門【ダイジェスト版】10分で理解するReduxの基礎
概念を理解するのは少し苦労しましたが、とっても便利です!
しかし、Redux では Reducer に「APIを呼び出す」ことをしてはいけない..と書かれています。
API の結果で状態を変えたい時はどうするんだ..とたどり着いたのが redux-saga というミドルウェアでした。(同じようなミドルウェアに redux-thunk, redux-promise があります)
redux-sagaで非同期処理と戦う
React + Reduxにおける非同期処理
ここまで分かって、実装である程度のことができる...と自信を持てるようになりました。
コンポーネント設計
一番最初、画面単位でコンポーネントを作っていました。(複雑だったら、分割すればいいよねー的なノリ)
そして、部品をコンポーネント化していくのですが、メンテナンスが上手くいかなかったです。
- 似たようなコンポーネントの二重管理になる
- コンポーネントがどのコンポーネントから使われているかわからない
似たようなコンポーネントの二重管理になる
2つの画面に似たものがあるけど、画面が違うことによって微妙に挙動が異なる。
そうなったときに、別にしてしまっていて、二重管理が発生している。
コンポーネントがどのコンポーネントから使われているかわからない
画面ごとに微妙にコンポーネントが違ってたりするときに、ある程度共通化するために
コンポーネントを作っていくと、コンポーネントの構造が全体として歪になります。
そうすると、コンポーネントがどのコンポーネントを使っているのか...ということが分かり辛くなります。
どうすればいいのか?
そこで、調べてみると、Atomic デザインというものに到達します。
Atomic Designを使ってReactコンポーネントを再設計した話
しかし、定義自体が明確ではなく、本当に考えずに適用すると苦しみます。
まず、Atom, Molecules, Organisms, Templates, Pages という5階層が基本ですが、
全ての画面をこのように組めというわけではありません。現実的には全て5階層で組むとかなり冗長な画面も発生します。
また、Atom は、最小単位ということで理解しやすいですが、
Molecules, Organisms の差はなんぞや?...ということが一番の問題です。
これに関しては、自分は明確に切ることができなかったので、
- Organisms: それ単体でも業務的に意味のあるコンポーネント
- Molecules: Atom を組み合わせてはあるけど、業務的に意味のないコンポーネント
という風に Molecules を Atom として作っておきたいけど、分離したものも必要だ!という場合に使っていました。
とはいえ、そんなケースを扱うことはほぼなかったので、Molecules はほとんどなかったです。
これにより、メンテナンス可能なアプリを作る自信が出てきました。
React native パッケージ
ReactNative では、様々な有名なパッケージがあります。例えば
- [React Native Elements] (https://reactnativeelements.com/)
- React Navigation
react-native-camera- react-native-snap-carousel
この辺りのパッケージを知識として持っておけば、コストを最小にできると思います。
(また、出来るだけ要件をパッケージ側で実現できるように寄せられるとなお良し)
しかし、中には パッケージが管理されていないものもあります。
仮にそういったものを使うと、現バージョンの ReactNative で動くかどうかの検証、
いざ何か起こった時の対応というのがリスクとして存在します。
このため、昔の記事でよく紹介されていても、放置されているものは正直使い辛いです。
そんな時は作ってしまうのも一つの対策だと思います。
自身の経験では、評価する時の星(Rating)を画像に載せて欲しい、そのときに背景を透過色にして欲しい
という要望があったんですが、React Native Elementsでは対応できず、古いパッケージもちょっと怖い。
..ということで、自身でコンポーネントを作ったことがあります。
ReactNative バージョンに関する話
ReactNative バージョン上げるときは、結構覚悟を持ってやった方がいいです。
ReactNative は後方互換性は保証しません。また、そこそこ破壊的だと自分は思っています。
自分は(2019/8月ごろ)Androidの64bit対応が必要になり、バージョン(v0.57→v0.60にした)をあげました。(開発開始からAndroidアプリがアップロードできなくなるまで放置されていた)
コンパイルエラー出ていないか、機能が壊れていないか、デザインはどうか、iOS側に影響はないか...。
ReactNativeのAndroid 64bit対応時に読んでおきたいメモ
こちらのバージョンあげた理由は、「Androidアプリは64bitアプリしかできなくなった」
..っていう、理由でしたが、このように、ReactNative 上の理由以外にも、Apple, Google のポリシー変更によってバージョン上げざるを得ないことがあります。
古いバージョンで開発していると、大変な影響を受けることになります。
長くメンテナンスをするのであれば、バージョンアップはこまめにやりましょう...。
iOS/Androidアプリ構築に関する知識
ここまでは TypeScript で各部分のことに関して記載してきましたが、デプロイに関する話です。
まず、iOSアプリをリリースするのであれば、iOSの証明書周りは複雑ですが必須です。
[iPhone] iOS, Certificate 証明書を作ってみる
あと、顧客にテストビルドを見てもらうには下記の方法があります。
- adhoc 証明書によるビルド
- TestFlight を使う
ただし、TestFlight を使うには、AppleStore にアプリ登録が必要なので、
そこまでしたくない場合は、「adhoc 証明書によるビルド」を使うことになります。
Apple 側では、このようなテストアプリを不特定多数に提供されないためか?
起動できるDeviceIDの設定を証明書に含めています。この辺りを知らないと
提供したアプリが動かない、という事態に陥ります...。
基本的に Expo で作ってあれば、これ以降はあまり自分は嵌りませんでした。
Expo では、証明書は作ってくれますし、iOSアプリへの変換・Androidアプリの変換は
Expo側で行ってくれるので、この辺りの面倒ごとがかなり改善されます。
なのでもし、React Native CLI で開発する場合 (もしくは Expo で reject して開発する場合)は、
iOSのビルドに関する知識が必要です(xcode設定, Cocoapod, Build設定など)
また、Androidのビルド(gradle)に関する知識も必要です。
もし、ReactNative 側に package がインストールされていなかったりすると、
iOSアプリのビルド時にリファレンスエラーが出たりするので、ビルドエラーが起こったときは結構苦労します。
なので、自分は Expo 以外の開発は現在はほぼ行っていません。
ReactNative CLI を使うケースとしては、Expo で対応できない..というケースですが、
一般的なアプリはほぼそういった要件はありませんので。
仮にあったとしても、要件次第では Native アプリ(Swiftで)作ってかもしれません。
まとめ
ReactNative におよそ1年少し関わって、すごく苦労した話を中心に書きました。
ReactNative のいいところは、1つのソースコードから2つのプラットフォームを作れる手軽さです。
スモールスタートでアプリを作っていきたい、といった要望にはマッチすると思います。
パフォーマンスを求められるもの、最新技術を用いたい場合には、使い辛いですが、
選択肢の一つしては、これからも関わっていきたいと思います。