【Firebase】リアルタイム更新されるチャットアプリを作成してFirebaseを学ぶ(Aauthログインも)

プログラミング初心者の勉強ブログ #118

Firebaseを使って簡易的なチャットアプリを作成したのでまとめる。リアルタイム更新はもちろん、DBもストレージもあって、APIも少ない手間で実装できるしFirebaseすげーって感じでした。

 

目次

[toc]

 

Firebase

firebase

https://firebase.google.com/

 

G’sでそのうち習うっぽいが、早めにやっておこうと思いリアルタイム更新されるチャットアプリ的な物を作ってみることにした。

 

Firebaseで作成したもの

stockidea

stock idea

とりあえず動くが、何箇所か意図せず起こる挙動がまだあるので、下に載せているコードは参考程度。

 

 

firebase

Firebaseを使うと、JSでリアルタイムな画面表示を更新できるようなものを作成できる。Oauthによるログインも少ないコードで実装が可能。ちょっとしたアプリなら無料枠内でリリースとかできるんじゃないかって思う。機能多くてまだあまりよくわかってないが、Railsよりは少なくとも実装が簡単だった。小規模なものであればRails使わないでFirebase使った方が良さげなのかもしれん。Oauth実装とかもだいぶ楽。

 

Firebase Notificationsをやめた4つの理由 – Qiita

それでもFirebaseを使うべき5つのメリット – Qiita

Qiitaをいろいろと読んでみたもののあまり理解することができなかった。

 

Firebaseでバックエンドエンジニア不在のアプリ開発 クックパッドが体感した、メリットと課題 – エンジニアHub|若手Webエンジニアのキャリアを考える!

この記事が一番参考になった。というより面白かった。

 

コード

結構いろいろと調べた。Firebaseの仕様が高頻度で変わっているからなのかもしれないが、調べても過去の情報とかが多く、今これで書いても反映されないわ、って何回もなった。

Firebase のガイド | Firebase

公式のガイドが一番確実な情報を載っけてくれているが、とても探しづらかった。YouTube APIとかのリファレンスの方がよっぽど探しやすかった気がする。先にも書いたが、とりあえず動くが何箇所か意図していない挙動がある。コンソールで「firebase.INTERNAL.registerAppHook is not a function」と言う、なんかよくわからないエラーもまだ出てくる。

 

main.js

const init = function() {
  setConfig();
  setLoginBtn();
  setUser();
};

// firebaseの初期設定
const setConfig = function() {
  const firebaseConfig = {
    apiKey: "xxxxxxxxxxxxxxxxxxxx",
    authDomain: "xxxxx.firebaseapp.com",
    databaseURL: "https://xxxxx.firebaseio.com",
    projectId: "xxxxx",
    storageBucket: "xxxxx.appspot.com",
    messagingSenderId: "xxxxxxxx",
    appId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  };
  firebase.initializeApp(firebaseConfig);
};

// ログインボタンのイベント
const setLoginBtn = function() {
  $('#loginBtn').on('click', function() {

    // この2行が大事。Twitter Oauthログイン画面にリダイレクトされる
    const provider = new firebase.auth.TwitterAuthProvider();
    firebase.auth().signInWithRedirect(provider);

    setPreloader();
    setUser();
  });
};

// ユーザー情報取得
const setUser = function() {

  // onAuthStateChanged() でユーザーのログイン状態を判別できる
  firebase.auth().onAuthStateChanged(function(user) {
    this.user = user;
    if (this.user) {
      // ユーザーがログインしているとき
      setPreloader();
      $('.logoutView').addClass('hide');
      $('.loginView').addClass('show');
      $('#username').html(this.user.displayName);
      setRef();
      setLogoutBtn();
      setSendBtn();
      renderIdeas();
    } else {
      // ユーザーがログインしていないとき
      $('#loginBtn').css('display', 'block');
    }
  });
};

// firebase.database().ref()でfirebaseのDBを参照できる
const setRef = function() {
  this.ideasRef = firebase.database().ref();
};

// ログアウトボタンのイベント
const setLogoutBtn = function() {
  $('#logoutBtn').on('click', () => {

    // サインアウト
    firebase.auth().signOut();

    $('.logoutView').removeClass('hide');
    $('.loginView').removeClass('show');
  });
};

// 送信ボタンのイベント
const setSendBtn = function() {
  $('#send').on('click', () => {

    // pushでDBに値を保存
    this.ideasRef.push({

      // firebase.auth().currentUser.displayNameでログインユーザーのTwitterアカウント名取得
      userName: firebase.auth().currentUser.displayName,

      title: $('#title').val(),
      text: $('#text').val(),
    });
    $('#title').val("");
    $('#text').val("");
  });
};

// 投稿のレンダリング
const renderIdeas = function() {
  // .on('child_added', {})でDB内全てのデータを選択
  this.ideasRef.on('child_added', function(data) {
    const v = data.val();
    const k = data.key;
    const idea = `<div class="idea" id='${k}'><div class="title">${v.title}</div><div class="user">${v.userName}</div><div class="content">${v.text}</div></div>`;
    $('#output').prepend(idea);
    removePreloader();
  });
}

// ローダー
const setPreloader = function() {
  $('#preloaderBg').css('z-index', '1');
  $('#preloaderBg').show();
  $('#preloader').show();
};

const removePreloader = function() {
  $('#preloaderBg').fadeOut(800);
  $('#preloader').fadeOut(300);
  setTimeout(() => {
    $('#preloaderBg').css('z-index', '-1');
  }, 800);
}
 
$(() => {
  init();
});

$(window).on('load', () => {
  removePreloader();
});

 

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>stockidea</title>
  <link href="https://fonts.googleapis.com/css?family=Noto+Sans+JP" rel="stylesheet">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
  <link rel="stylesheet" href="./css/style.css">
</head>
<body>
  <!-- preloader -->
  <div id="preloaderBg">
    <div id="preloader">
      <img src="./img/preloader.gif">
    </div>
  </div>
  <!-- /preloader -->

  <div class="container flex centering">
    <!-- ログイン前 -->
    <div class="logoutView flex centering">
      <h1 class="title">stockidea</h1>
      <div class="btn" id="loginBtn"><span><i class="fab fa-twitter"></i> Login</span></div>
    </div>
    <!-- /ログイン前 -->
    
    <!-- ログイン後 -->
    <div class="loginView borderBox">
      <header class="header flex">
        <div class="title">stockidea</div>
        <div id="username"></div>
        <div class="btn" id="logoutBtn"><span>Logout</span></div>
      </header>
      <div class="content borderBox">
        <div class="input borderBox">
          <input id="title" type="text" placeholder="Title">
          <textarea id="text" rows="5" placeholder="Content"></textarea>
          <button id="send">Post</button>
        </div>
        <div id="output" class="flex borderBox"></div>
      </div>
    </div>
    <!-- /ログイン後 -->
  </div>

  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>

  // firebase-app.jsは必ず必要
  <script src="https://www.gstatic.com/firebasejs/5.11.1/firebase-app.js"></script>

  // firebase-auth.jsはログイン機能実装の場合必要
  <script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-auth.js"></script>

  // firebase-database.jsはDB使うなら必要
  <script src="https://www.gstatic.com/firebasejs/3.1.0/firebase-database.js"></script>

  <script src="./js/main.js"></script>
</body>
</html>

 

まとめ

JSだけで実装できるのが楽しい。バックエンドやった感覚は少ない。データ構造をもう少し複雑にして、また挑戦してみたい。

以上ありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA