今更React Nativeをやる(導入や環境の基礎)

# なぜ今更React Nativeをやるのか
個人開発でやってみたいことがどうしてもアプリが必要だから。です。
Flutterも良さそうじゃん？と思ったんですが最近Reactを使った案件に入ったりしてVue派だったのがReact派に少し傾きつつありどうせならReact Nativeを使ってみたいと思って選びました。

# 環境
Macbook Pro 2019
Intel i9
Ventura 13.2
検証端末
iPhone 14 Pro Max iOS 17.3.1
家に転がってたOPPO A54 5G Android 12

# 知識と経験
Javaを5年くらい
VueをメインにたまにReactを触りつつ4、5年
ちょいちょいVue+Firebaseの経験あり

# この記事でやること
- react nativeのTypeScriptでのプロジェクトの作成
- firebaseの導入
- ルーティングの設定
- ルーティングの動作確認

# 導入
(expo goはスマホに入れておきましょう)

https://reactnative.dev/docs/environment-setup

これに則って導入してみたところ普通にエラー発生。
スクショは撮ってないけどPCとスマホ同じWifiか？みたいなエラー。
npm installしたら直りました。

ただTypeScriptを使いたいのでやりなおし。

https://reactnative.dev/docs/typescript


>New projects created by the React Native CLI or popular templates like Ignite will use TypeScript by default.

>TypeScript may also be used with Expo, which maintains TypeScript templates, or will prompt you to automatically install and configure TypeScript when a .ts or .tsx file is added to your project.

React Native CLIやIgniteの一般的なテンプレートで作られた新しいプロジェクトではデフォルトでTypeScriptになる。

IgniteっていうReact Nativeのフレームワークがあるみたいです。

....expoは？

https://docs.expo.dev/guides/typescript/

expoはどうやらexpoのドキュメント内に書いてあるみたいでした。

```
npx create-expo-app -t expo-template-blank-typescript
```

```
$ npx create-expo-app -t expo-template-blank-typescript
✔ What is your app named? … my-app
✔ Downloaded and extracted project files.
> npm install
npm WARN deprecated @npmcli/move-file@1.1.2: This functionality has been moved to @npmcli/fs
npm WARN deprecated @babel/plugin-proposal-optional-catch-binding@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.
npm WARN deprecated @babel/plugin-proposal-nullish-coalescing-operator@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
npm WARN deprecated @babel/plugin-proposal-numeric-separator@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.
npm WARN deprecated @babel/plugin-proposal-class-properties@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
npm WARN deprecated @babel/plugin-proposal-logical-assignment-operators@7.20.7: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.
npm WARN deprecated @babel/plugin-proposal-optional-chaining@7.21.0: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
npm WARN deprecated @babel/plugin-proposal-async-generator-functions@7.20.7: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.
npm WARN deprecated @babel/plugin-proposal-object-rest-spread@7.20.7: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.

added 1169 packages, and audited 1170 packages in 44s

65 packages are looking for funding
  run `npm fund` for details

5 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

✅ Your project is ready!

To run your project, navigate to the directory and run one of the following npm commands.

- cd my-app
- npm run android
- npm run ios
- npm run web

```
プロジェクト名を入力するだけであら簡単！

npmを使ってる場合はpackage.jsonにスクリプトを追加する必要があるらしい。
```
{
  "scripts": {
    "ts:check": "tsc"
    ... 
  }
}
```
プロジェクトの型チェック？のために
```
npm run ts:check
```
を実行するらしい（なにこれ）

```
[user@MacbookPro:~/workspace/my-app]+[main]
$ npm run ts:check

> my-app@1.0.0 ts:check
> tsc

```

なんやねん

> When you create new source files in your project you should use the .ts extension or the .tsx if the file includes React components.


新しいソースファイルを作る時は.tsファイルか、Reactコンポーネントを含んでいるなら.tsxで作るようにとのこと。

# とりあえず動かしてみる
```
[user@MacbookPro:~/workspace/my-app]+[main]
$ npm run ios

> my-app@1.0.0 ios
> expo start --ios

Starting project at /Users/user/workspace/my-app
Starting Metro Bundler
? Xcode must be fully installed before you can continue. Continue to the App Store? ›
```
expoアプリでできないんですか！？

-> npm startで無事QRコードが表示されました。

![IMG_4267.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/ccafee7f-4722-0a04-edf6-847dd23dd56d.png)

✌️

![スクリーンショット 2024-03-26 23.03.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/f97ca2a6-06e6-7401-5722-3a8673f76ef7.png)

App.tsxになっていて無事TypeScriptでReact Nativeプロジェクトが作れました。

# 触ってみる
チャットアプリを作ってみることにします。

バックエンド？というかデータ管理とかはFirebaseでやります。

firestoreとRealtime databaseどっちがいいか・・・

https://firebase.google.com/docs/database/rtdb-vs-firestore?hl=ja

> Cloud Firestore は、Firebase のモバイルアプリ開発用の最新データベースです。直感的な新しいデータモデルで Realtime Database をさらに強化しています。Cloud Firestore は、Realtime Database よりも多彩で高速なクエリと高性能なスケーリングが特長です。

> Realtime Database は従来からある Firebase のデータベースです。リアルタイムのクライアント間同期が必要なモバイルアプリのための、効率的でレイテンシが低いソリューションです。

ほなRealtime databaseかあ・・・

![スクリーンショット 2024-03-26 23.12.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/96dcca51-38a3-7874-f3ae-1513fbf69042.png)

一応質問に答えてどっちの方がいいか教えてもらえるみたいです。
個人的に
firestore
- ユーザー情報やアカウント情報
- チャットルームID

Realtime database
- チャットルーム


でやったほうが強そうな気はしてます。できるんでしょうか。

画面はとりあえず以下の4つでやります。
- ログイン
- 会員登録
- とりあえずユーザーを選択する画面
- チャットルーム

## Firebaseの導入
https://docs.expo.dev/guides/using-firebase/


> There are two different ways you can use Firebase in your projects:
>Using Firebase JS SDK
>Using React Native Firebase
>React Native supports both the JS SDK and the native SDK. 

FirebaseのJS SDKとReact Native Firebaseの二種類があってReact Nativeはどちらもサポートしてるらしい。
そりゃそうだ。

> Prerequisites
> Before proceeding, make sure that you have created a new Firebase project or have an existing one using the Firebase console.


前提としてfirebaseコンソールでプロジェクトを作成する必要がある。

この辺をやりましょう（手順は割愛）
- firebaseプロジェクトの作成
- Authenticationを開始してメールアドレス/パスワードログインとGoogleログインを有効化
- firestoreを有効化
- realtime databaseを有効化

firestoreとrealtime databaseはどっちか不要になるかも。

#### React Native FirebaseとFirebase JS SDKどっちがいいか

> The Firebase JS SDK is a JavaScript library that allows you to interact with Firebase services in your project. It supports services such as Authentication, Firestore, Realtime Database, and Storage in a React Native app.


Firebase JS SDKはプロジェクト内でFirebaseサービスを使用するためのJavaScriptライブラリ。React Nariveアプリ内でAuthentication, firestore, realtime database, storageのサービスをサポートする。

---
>React Native Firebase provides access to native code by wrapping the native SDKs for Android and iOS into a JavaScript API. Each Firebase service is available as a module that can be added as a dependency to your project. For example, the auth module provides access to the Firebase Authentication service.


React Native FirebaseはAndroidとiOSのネイティブSDKをJavaScript APIにラップしてネイティブコードへのアクセスを提供する。Firebaseのそれぞれのサービスはプロジェクト内に依存関係として追加できるモジュールとして使える。例えばauthモジュールはFirebase Authenticationサービスへのアクセスを提供する。

---

正直ネイティブコードはわからないのでFirebase JS SDKにします。

### Firebase JS SDKの導入

> The following sub-sections use firebase@9.x.x. Expo SDK does not enforce or recommend any specific version of Firebase to use in your app.
If you are using an older version of the firebase library in your project, you may have to adapt the code examples to match the version that you are using with the help of the Firebase JS SDK documentation.

firebase@9.x.x.を使うらしいです。
古いバージョンのfirebaseを使ってたらそのバージョンに合わせてコードを修正する必要があるかもしれないとのこと。


1.SDKのインストール
```
npx expo install firebase
```
2.firebaseお決まりのinitialize 
- firebaseインスタンスを初期化するためにconfigオブジェクトを作成して、`firebase/app`からインポートした`initializeApp()`に渡す
- configオブジェクトに色々なキーが必要なのでfirebaseプロジェクトからウェブアプリを登録する
- ルートディレクトリにfirebaseConfig.jsを作成してコピペ
```
import { initializeApp } from 'firebase/app';

// Optionally import the services that you want to use
// 必要に応じて使いたいサービスをインポートする
// import {...} from "firebase/auth";
// import {...} from "firebase/database";
// import {...} from "firebase/firestore";
// import {...} from "firebase/functions";
// import {...} from "firebase/storage";

// Initialize Firebase
// firebaseを初期化
const firebaseConfig = {
  apiKey: 'api-key',
  authDomain: 'project-id.firebaseapp.com',
  databaseURL: 'https://project-id.firebaseio.com',
  projectId: 'project-id',
  storageBucket: 'project-id.appspot.com',
  messagingSenderId: 'sender-id',
  appId: 'app-id',
  measurementId: 'G-measurement-id',
};

const app = initializeApp(firebaseConfig);
// For more information on how to access Firebase in your project,
// see the Firebase documentation: https://firebase.google.com/docs/web/setup#access-firebase
```
![スクリーンショット 2024-03-26 23.53.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/3902355f-c98d-66ce-c1d9-e4ae70259aa4.png)
何やらエラーが出てますな。
![スクリーンショット 2024-03-26 23.55.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/6c61fde7-0962-f696-1b56-4243b4d30863.png)
なおりました。

3.Metroの設定
firebaseのバージョンが9.7.x以上の場合はFirebase JS SDKが正常にバンドルされているかを確認するために以下の設定をmetro.config.jsに追加する。

```
const { getDefaultConfig } = require('@expo/metro-config');

const defaultConfig = getDefaultConfig(__dirname);
defaultConfig.resolver.sourceExts.push('cjs');

module.exports = defaultConfig;
```

```
npx expo customize metro.config.js
```

---

スマホで開いたらエラーもなく動きました。

## 導入はできたのでとりあえず画面を作っていく
とはいえReactでFirebase使ったことないな・・・ということでこのあたりからが勉強らしい勉強。


### ルーティング
ルーティングはどうしようってことで調べてたらExpo Routerなるものがあるそうで。

https://docs.expo.dev/router/installation/#quick-start

#### 依存関係も含めていろいろインストール

```
npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar
```


#### エントリーポイントの設定
SDK49以上
package.jsonのmainを変更する。
```
{
  "main": "expo-router/entry"
}
```
これでエントリーポイントがapp/_layout.jsになるらしい。



・・・.js？
TypeScript入れたけど大丈夫か？

![スクリーンショット 2024-03-27 0.22.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/9e88bc5b-448a-514d-a0a1-fb000a21ec47.png)

試しにエントリーポイントに指定した名前でtsxにしてみたところ普通に表示できました。ありがとうExpo。

![スクリーンショット 2024-03-27 0.23.58.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/7429e62d-3259-34f1-0d25-35805e0f37c5.jpeg)

4番はWebでは開かない想定なのでスルーします。

babel.config.jsを変更
babel-preset-expoをpresetとして使うかbabel.config.jsを消してくださいとのこと。
元々なってたのでOKです。

### ページの作成
https://docs.expo.dev/router/create-pages/


この辺は

https://zenn.dev/tellernovel_inc/articles/60a6e7c41fd8a3

で詳しく説明してくれてます。

expoドキュメント通りでいきます一旦

appディレクトリにファイルが作成されると自動的にルーティングしてくれるみたいです。
appディレクトリ
index.js　・・・　'/'
home.js　・・・ '/home'
[user].js ・・・　'/expo'や'/evanbacon'のような動的パスにマッチする

settingsディレクトリ
index.js ・・・ '/settings'


・・・？

[user].jsの説明がイマイチわからなかったので
https://zenn.dev/tellernovel_inc/articles/60a6e7c41fd8a3
をみてみると

[]はパスパラメータを表してるみたいですNextの経験はないのでぴんとこな。

要するにappディレクトリのルートに対してパスパラメータを渡した場合にここに辿り着くということみたいです。

どうやら_layout.tsxはその階層のデフォルトの見た目を設定できるらしいので確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/0e793de3-5a2a-a160-e265-e535da3ffbf8.png)

こんな感じに設定

すると画面は
![スクリーンショット 2024-03-27 1.06.10.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/91c2874c-8b8d-e9f5-6882-64ef9a415834.jpeg)
上下に表示されてますね。
`<slot />`はそのページに表示するものなのでここではindex.tsxの中身が表示されます。
ルートが別のページになっていたらそのページがslotの中に入ってくるって寸法ですね。


---
では当初の予定通りページを作ってみます。

()についてはZennのExpo Routerの記事参照
ログイン... (auth)/login.tsx
会員登録...(auth)/register.tsx
ユーザー選択画面...(app)/index.tsx
チャットルーム...(app)/[id].tsx

こんな感じでいきます。

とりあえず画面が変わるか確かめるためにページ遷移するだけのボタンを作ってみます。

「react native ボタン」と

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/318c32db-e224-7bc2-39f0-dfd6d45e3a19.png)

![スクリーンショット 2024-03-27 21.50.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/d418902e-1815-628f-5afd-3a0f022c6907.png)


![スクリーンショット 2024-03-27 21.52.33.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563342/2640305b-33f4-a73e-a994-8429bde81569.jpeg)

無事に遷移してパラメータも渡されていました。

次は画面を作り込んでいくんですが長くなったので一旦この辺で終わります。