ほぼテンプレートの状態からシンプルにRiot.jsとFirebaseを連携する


前提条件

・macOS Catalina
Riot.js: SPA テンプレート
Firebase: Firebase Cloud Functions

目標

Riot.jsからFirebaseのCloud Functionsを叩いて、レスポンスを画面に反映する

結果

最後まで読んで結果にがっかりさせるとあれなので先に結果から

これが

こう!😇😇😇

手順

Firebaseの修正

CORSの許可

実際には完全に一度引っかかってから設定していますがご愛嬌。
responseに各ヘッダをセット。

  // CORS用にAccess-Control-Allow系ヘッダを追加
  response.set('Access-Control-Allow-Origin', 'http://localhost:3000'); // localhostを許可
  response.set('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS, POST'); // DELETEだけは拒否
  response.set('Access-Control-Allow-Headers', 'Content-Type'); // Content-Typeのみを許可

レスポンスの修正

前回はレスポンスに素のテキストを設定していたので、JSON形式で返却するように修正

  // response.send("Hello from Firebase!"); 下記に変更
  response.send({message: "this is json message"});

JSON形式で返却されることを確認(POSTMAN)

Riot.jsの修正

Riot.jsのコンポーネントを追加

テンプレートで作成されているタブをそのまま利用しても良かったのですが、勉強も兼ねてコンポーネントを追加します。
まずはコンポーネントのファイルを作成。(命名が💩なのは目をそらしてください)

firebase-str.riot
<firebase>
  <h1>Firebase Response</h1>
  <p><b>nothing</b></p>
  <button>get firebase</button>
</firebase>

次に追加したfirebaseというコンポーネントを表示する際のパスを追加

pages.js
export default [{
  path: '/',
  label: 'Home',
  componentName: 'home'
}, {
  path: '/about',
  label: 'About',
  componentName: 'about'
}, {
  path: '/firebase',
  label: 'Firebase',
  componentName: 'firebase'
}]

最後にapp.riotのexport default部分に今回のFirebaseという名前のコンポーネントを追加

app.riot
/* ~~~(省略)~~~ */

  <script>
    import { Router, Route, route, toRegexp, match } from '@riotjs/route'
    import lazy from '@riotjs/lazy'
    import Loader from './components/includes/loader/loader.riot'
    import NotFound from './pages/not-found.riot'
    import pages from './pages'

    export default {
      components: {
        Router,
        Route,
        NotFound,
        Home: lazy(Loader, () => import(
          /* webpackPrefetch: true, webpackChunkName: 'pages/home' */
          './pages/home.riot'
        )),
        About: lazy(Loader, () => import(
          /* webpackPrefetch: true, webpackChunkName: 'pages/about' */
          './pages/about.riot'
        )),
        Firebase: lazy(Loader, () => import(
          /* webpackPrefetch: true, webpackChunkName: 'pages/firebase-str' */
          './pages/firebase-str.riot'
        )),
      },

/* ~~~(省略)~~~ */

これでコンポーネントの追加が完了です。
この時点で画面上部のタブが追加されて、Firebase取得用に新たに追加した画面の表示ができます。
(現時点ではただのボタンなのでGET FIREBASEを押下しても何も起こりません。)

表示している文字列をステート管理に変更

まずはnothingの文字をstateで管理するように変更

firebase-str.riot
<firebase>
  <h1>Firebase Response</h1>
  <p><b>{ state.firebase }</b></p>
  <button>get firebase</button>

  <script>
    export default {
      state: {
        firebase: 'nothing'
      },
    }
  </script>
</firebase>

画面上では変化はありませんが、これでthis.updateでfirebaseの値を更新すると文字列が変更されるようになっています。

Fetchを利用してFirebaseからJSONを取得する

・get_firebaseという関数を追加し、関数内でFirebaseへのFetchを行う。Fetchで得られたレスポンスのJSONからmessageを取得し、stateのfirebaseの値を更新する。(nothing から this is json message となっている)

・ボタンのonClickで追加した関数が呼び出されるように修正!

firebase-str.riot
<firebase>
  <h1>Firebase Response</h1>
  <p><b>{ state.firebase }</b></p>
  <button onclick={get_firebase}>get firebase</button>

  <script>
    export default {
      state: {
        firebase: 'nothing'
      },
      get_firebase() {
        const url = "http://localhost:5001/[URL]/helloWorld"
        fetch(url, {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json'
          }
        }).then((response) => {
          return response.json();
        }).then((json) => {
          this.update({
            firebase: json.message
          })
        })
        .catch(error => {
          alert(error)
        });
      },
    }
  </script>
</firebase>

これが

こう!😇😇😇(2度目)

これで目標達成です!🎉

おわりに

スムーズに実装してるように見える記事になってしまったけど実際には各手順で詰まってた(誇張)
個人的には最低限かつシンプルにコンポーネントの追加ができたかなと思ってます!

補足情報

Firebaseをローカルで実行する際は下記のコマンド
--only functions とすることでfunctionsのみをローカル起動してくれている。

$ firebase emulators:start --only functions

参考

FirebaseのCloud FunctionsでCORSが~とかAccess-Control-Allow-Originが~と言われたらこれ
Riot.js で外部の jsonファイルを読み込む:シンプルアップ工房
jQueryで書いたAjaxを、Fetch APIで書く:Learnプログ-マナビメモ-