Vue.js + Firebase Realtime Database v9

Vue.jsとFirebase RealtimeDatabaseを接続する方法を調べてみると、多くの記事の書き方が使えませんでした。
理由はバージョンの違いでした。

Firebase v9 ウェブバージョンを使う人向けのメモです。（2022/02/27現在）

# 前提

以下の記述を使う想定。

- node v16.13.0
- npm 8.1.2
- Vue.js 2.6
- Vue CLI
- Vue Router
- ウェブ向け Firebase v9
- Typescript

# 手順

## vue.jsプロジェクト作成

Vue CLIを使って、manualモードでプロジェクトを作成。

```
Vue CLI v4.5.13
┌───────────────────────────────────────────┐
│                                           │
│   New version available 4.5.13 → 4.5.15   │
│     Run npm i -g @vue/cli to update!      │
│                                           │
└───────────────────────────────────────────┘

? Please pick a preset:
  Default ([Vue 2] babel, eslint)
  Default (Vue 3) ([Vue 3] babel, eslint) 
> Manually select features
```

選択肢は以下のように選択しました。

```
? Check the features needed for your project: 
>(*) Choose Vue version
 (*) Babel
 (*) TypeScript
 ( ) Progressive Web App (PWA) Support        
 (*) Router
 (*) Vuex
 ( ) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing
```

フォルダ構成はこんな感じになります。

```
project
    ├ node_modules
    ├ public
    │   ├ favicon.ico
    │   └ index.html
    ├ src
    │   ├ assets
    │   │   └ logo.png
    │   ├ components
    │   │   └ HelloWorld.vue
    │   ├ router
    │   │   └ index.ts
    │   ├ store
    │   │   └ index.ts
    │   ├ views
    │   │   ├ About.vue
    │   │   └ Home.vue
    │   ├ App.vue
    │   ├ main.ts
    │   ├ shims-tsx.d.ts
    │   └ shims-vue.d.ts
    ├ .browserslistrc
    ├ .editorconfig
    ├ .eslintrc.js
    ├ babel.config.js
    ├ package-lock.json
    ├ package.json
    └ tsconfig.json
```

## firebaseをインストール

```
npm install firebase
```

実行するとpackage.jsonに`firebase`が追記されます。

```json:package.json
"dependencies": {
(省略)
    "firebase": "^9.6.7",
(省略)
},
```

## Realtime Databaseにアクセス

Realtime Databaseの内容は以下の想定です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224453/f0a3dde7-9393-1627-3b08-08b1ef940870.png)

プロジェクト作成時に生成された`main.ts`にfirebaseの初期処理を記載して、他のVueファイルでfirebaseを利用できるようにしています。

```ts:main.ts
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { initializeApp } from 'firebase/app'

Vue.config.productionTip = false

const firebaseConfig = {
  apiKey: '***************************************',
  authDomain: '*******************************',
  projectId: '***************',
  storageBucket: '***************************',
  messagingSenderId: '*************',
  appId: '******************************************'
}
const app = initializeApp(firebaseConfig)

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
```

プロジェクト作成時に生成された`About.vue`ファイルを使って表示を試しました。

```vue:About.vue
<template>
  <div class="about">
    <ul>
      <li v-for="todo in todos" :key="todo.id">
        {{ todo.id }}:{{ todo.todo }}
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import { getDatabase, ref, child, get } from 'firebase/database'

export default Vue.extend({
  name: 'About',

  data: () => ({
    todos: []
  }),
  mounted: function () {
    // 接続
    const db = getDatabase()
    const dbRef = ref(db)
    // データ取得
    get(child(dbRef, 'todos')).then((snapshot) => {
      if (snapshot.exists()) {
        this.todos = snapshot.val()
      } else {
        console.log('No data available')
      }
    }).catch((error) => {
      console.error(error)
    })
  }
})
</script>
```

## 結果表示

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224453/1b746c23-b073-f260-fad2-5b403a38a9f8.png)