FEエンジニアがReact Nativeを触ってみました
はじめまして、mediba FEエンジニアの楊です。 最近猫パンチ避け上手になっているので、猫を困らせています。
React Native初見
ネットで調べてみて、第一印象は「可愛いかった」です。
その他に感じた印象は下記です。
- facebookのcross-platformフレームワークで、1回書いたらAndroid、iOS、Web全部動くだろう。
- React Native(以下RN)という名前付けなので、React開発者にとって、使いやすいだろう という浅い認識で、チームメンバーと一緒にRNのプロジェクトを書いてみました。
React Native振り返る
ある程度コードを書いてみると、以下の事に気が付きました。
- バージョンアップが早い
- 最近のリリースを見ると1年間3個のメインバージョンがもうリリースされて、RNのバージョン管理が課題になりそう、特にキャッチアップには、互換性の問題が目の前に
- debugの難しさ
- Web開発と比べると、RNでよくみる真っ赤な画面のエラー画面あるが、それのメッセージだけで、フロントかネイティブかのエラーの判断は難しい
- 要素の高さがスクリーンの高さを超えたらスクロールできない
- Webだと生まれつきでスクロールできるけど、RNの場合一番外側にスクロール可能のエレメントでwrapしてあげないと
- iOSとAndroidにおいての違い
- ある程度RNがその違いを埋めてくれてますが、それぞれの環境に依存した処理がある(外部libで済む場合も)
- リストの選択
- RNのリスト、元々listViewとflatList二つもあって、listviewは性能的な問題で放棄されて、flatListが推奨されてます(実際カルーセルを作った際に困ってた)
つまり、RNは依存心の強い子でした。
印象的ポイント
RNを触ってみて、一番興味深いところというと、native codeで書いたSDKを扱える部分でした、いわゆるNative Module Bridgingというものです。 前述の通りある程度RNがiOSとAndroidの違いを埋めてくれてますが、それぞれのOSに依存したAPIはJSでの扱いは不可なものもあり、あるいはより高いパフォーマンス的、マルチスレッド的に作りたい場合、native moduleを介してそれを実現できます。
実際手を動かして、 公式ドキュメントをみながら、自分なりに簡単な「hello-world」を作ってみました。(学校でJavaを学んでたので、個人的に親切なAndroidを選んだ^^)
ステップ:
- 環境設定
- なんとなく動くnative code書く
- RNを介して、native moduleとして、JS側にに披露(expose)する
- JS側で呼び出し
環境設定
公式ドキュメントに沿って環境設定できます。JavaScript(以下JS)、TypeScript(以下TS)両方作れますが、 自分はTSのテンプレートを作りました(TS最高)
なんとなく動くnative code書く
環境設定終わりましたら、下記のandroidのフォルダで作業をしていきます(自分はJavaの構文あまり自信ないから、Android Studioでandroidフォルダーを開いてコードを書いているw)
android/app/src/main/java/com/awesomeproject
の配下でHelloModule.java
という新規Javaファイルを作ります。
ファイルの中身はこんな感じ:
public class HelloModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
HelloModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
public static void setTimeout(Runnable runnable, int delay){
new Thread(() -> {
try {
Thread.sleep(delay);
runnable.run();
}
catch (Exception e){
System.err.println(e);
}
}).start();
}
@ReactMethod
public void sayHelloToPopUp(String name) {
Toast.makeText(reactContext,"Hello World,"+name,Toast.LENGTH_LONG).show();
}
@ReactMethod
public void sayHelloAfterThreeSecond(String name, Promise promise) {
setTimeout(()->promise.resolve("Hello after 3 seconds,"+name),3000);
}
@NonNull
@Override
public String getName() {
return "HelloModule"; //この命名でNativeModulesに追加
}
};
とりあえず試しに、下記二つの関数を作ってみました。
- AndroidのToastを使って出力できる
sayHelloToPopUp
- Promiseを返す
sayHelloAfterThreeSecond
App(JS側)に披露(expose)する
init後に自動生成されたandroid/app/src/main/java/com/awesometsproject/MainApplication.java
の中身を見てみると
protected List getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
※ // packages.add(new MyReactNativePackage()); ←この行を解放
return packages;
}
既に用意してくれたPackage名でpackageを作ります。上記のファイルと同じフォルダー配下でMyReactNativePackage.java
のファイルを作成し、nativePackage作り、NativeModuleに先程作成したHelloModuleを追加すれば完成です。
public class MyReactNativePackage implements ReactPackage {
@NonNull
@Override
public List createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@NonNull
@Override
public List createNativeModules(
@NonNull ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
modules.add(new HelloModule(reactContext));
return modules;
}
}
JS側で呼び出し
最後の一歩は、App.tsxで使うことですね。
import { NativeModules } from 'react-native';
まずNativeModulesをimport,それから先程作ったsayHelloToPopUp
とsayHelloAfterThreeSecond
を呼び出します!
const { HelloModule } = NativeModules
const sayHello = React.useCallback((words)=>{
HelloModule.sayHelloToPopUp(words)
},[])
const sayHelloThreeSecondsLater = React.useCallback(()=>{
HelloModule.sayHelloAfterThreeSecond('lalalalala').then((res)=>sayHello(res))
},[])
...
<button title="{">
最後、rootでyarn androidすれば、起動を待ち、シミュレーターが立ち上がってアプリインストール完了、アプリでpressボタンをポチる
3秒後に添付画像のトーストが出てきます
感想
RNのようなクロスプラットフォームのフレームが宣伝したように、「一回書いたらどのプラットフォームでも動ける」という理想があるが、 実際にプロジェクトを作るに当たって、ネイティブアプリもフロントを全部理解し、一人でのiOS,AndroidとWeb全てのコードを書けることはありえない。 しかしRNを架け橋に、ネイティブチームとフロントチームを連携し、斬新なビッグ(B.I.G)フロントチームを生み出せるではないでしょうか。 ことわざの通り「理想なき者に成功なし」^^
