Firebase JavaScript SDK v8 → v9

# この記事は？
久しぶりにfirebaseを触ってみたらJavaScriptSDKのバージョンが9になっていて、使い方がだいぶ変わっていたので個人の備忘を兼ねて使い方を纏めたものです。
# 更新履歴
2022/01/03 Storeの記述例を追記した。
# v9で何が変わった？
具体例を挙げると、v9より前だと下記のような形だった。

```javascript
import firebase from 'firebase/app';
import 'firebase/database';

const firebaseApp = firebase.initializeApp({ /* （設定情報） */ });
const database = firebaseApp.database();
```

v9だと下記のようになる。

```javascript
import { initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";

const firebaseApp = initializeApp(firebaseConfig);
const database = getDatabase(firebaseApp);
```

以前のバージョンだとstorageとかdatabaseなどの該当モジュールをimportして、そのモジュールのメソッドから各機能を利用していたが、v9では必要な機能だけをimportする形式に変わった。
これによって、必要なものだけがimportされるため、ビルド後のファイルが軽くなり、パフォーマンスの向上に繋がる（その反面、書くのはちょっとめんどくさくなった印象）。

# 各モジュールの記述例

## auth

```javascript
import { initializeApp } from "firebase/app";
import {
  getAuth,
  setPersistence,
  browserLocalPersistence,
  signInWithEmailAndPassword,
} from "firebase/auth";

// firebaseインスタンス生成
const firebaseApp = initializeApp(firebaseConfig);
// authインスタンス生成
const auth = getAuth(firebaseApp);

// 認証の永続化（browserLocalPersistenceだと明確にログアウトするまで維持される）
setPersistence(auth, browserLocalPersistence).then(() => {
  // メールアドレスとパスワードでサインイン
  return signInWithEmailAndPassword(
    auth,
    this.loginEmail, // フォームで入力されたEmail
    this.loginPassword  // フォームで入力されたパスワード
  )
    .then(() => {
      /* サインイン成功後の処理 */
    })
    .catch((error) => {
       /* サインイン失敗後の処理 */
    });
});

```

## database（Realtime Database）

```javascript
import { initializeApp } from "firebase/app";
import { getDatabase, ref, onValue, update } from "firebase/database";

// firebaseインスタンス生成
const firebaseApp = initializeApp(firebaseConfig);
// databaseインスタンス生成
const database = getDatabase(firebaseApp);

// データの変更を検知（=データ取得）
onValue(ref(database, "testdata"), (data) => {
    const rootList = data.val();
    const key = data.key;
    
    if (rootList != null) {
        Object.keys(rootList).forEach((val, key) => {
            /* データ1件処理 */
        }
    }
});

// データ更新
update(ref(database, "testdata/key1"), {
  user: {
    [this.userid]: {
      done: true,
    },
  },
});
```

## storage

```javascript
import { initializeApp } from "firebase/app";
import {
  getStorage,
  ref as storageRef, // refがdatabaseのrefと重複するので別名定義
  getDownloadURL,
} from "firebase/storage";

// firebaseインスタンス生成
const firebaseApp = initializeApp(firebaseConfig);
// storageインスタンス生成
const storage = getStorage(firebaseApp);

// StorageからダウンロードURLを取得
getDownloadURL(storageRef(storage, imageURL))
  .then((url) => {
    /* 成功した時の処理 */
  })
  .catch((error) => {
    /* エラー時の処理 */
  });
```

## Store

```javascript
import { initializeApp } from "firebase/app";
import {
  getFirestore,
  doc,
  getDocs,
  collection,
  query,
  getDoc,
  setDoc,
  orderBy,
} from "firebase/firestore";

// firebaseインスタンス生成
const firebaseApp = initializeApp(firebaseConfig);
// storeインスタンス生成
const db = getFirestore(firebaseApp);

// データをdatetime列でソートして取得
const q = query(collection(db, "radio"), orderBy("datetime"));
const querySnapshot = await getDocs(q);

// 取得したデータを一件ずつ処理
querySnapshot.forEach(async (d) => {
  console.log(d.data());

  // サブコレクションから１件だけ取得
  const subDoc = doc(db, "radio/" + d.id + "/user", this.userid);
  const docSnap = await getDoc(subDoc);

   if (docSnap.exists()) {
       console.log(docSnap.data());
   }
   
   // サブコレクションにデータ追加（同一キーのデータがある時は更新）
   setDoc(subDoc, {
       done: e.target.checked,
   });
});



```