【Next.js+Firebase】
自身の勉強過程を
無理やり作品にしていく
Vol.3:今度こそ!Firebase Authentication編

  • 【Next.js+Firebase】
    自身の勉強過程を無理やり作品にしていくVol.3:今度こそ!Firebase Authentication編

    Firebase

    どうも!こんにちは!

    前回、Firebase Authenticationの実装について書こうとしましたが、そもそものFirebaseとの連携が必要になるので、
    Firebaseとの連携で終わりました。。

    そのため今回こそ、Firebase Authenticationの実装について書いていきます!

    それではスタートです!

    Firebase Authentication実装

    実装するにあたりまずは、FIrebaseのドキュメントを確認しましょう。

    ちなみに前回でFirebaseとの連携や初期化完了している形で進みますので、まだやっていなければ、前回の記事を参考にまずは準備をしてください。

    ログインを実装

    Firebaseのドキュメントにも書かれているように、まずはGoogle プロバイダ オブジェクトのインスタンスとやらを作成していきます。

    // pages/index.tsx
    import type { NextPage } from 'next';
    import { useRouter } from 'next/router';
    import { fbApp, auth } from '../../../firebase';
    
    export const Home: NextPage = () => {
      const router = useRouter();
      // ボタンクリック時のログインイベント
      const handleLogIn = () => {
        // インスタンスを生成
        const provider = new fbApp.auth.GoogleAuthProvider();
        // リダイレクトしてログインを行うため、signInWithRedirectを使用する
          auth.signInWithRedirect(provider);
          router.push('/login');
        };
    
        return (
          <>
            <button onClick={handleLogIn} ログイン</button>
          </>
        );
      };
      
      export default Home;

    ログインはボタンをクリックした際に発生させるので、handleLogInというクリックイベントを作成します。

    その中でGoogle プロバイダ オブジェクトのインスタンスを作成して、ログイン方法としてリダイレクトしてログインするようにsignInWithRedirectを使用しています。

    そしてログインができたら、ログイン後のページに遷移するように、Next.jsのuseRouterを使用してログイン後のページに遷移させています。

    これだけで、ボタンをクリック後にGoogleのログインページにリダイレクトし、
    Googleログインを行いログインできれば、ログイン後のページに遷移するということができると思います。

    ログアウトボタンの表示を実装

    ログインができるということはログアウトもできないといけません。

    ログインが成功したら、
    ログアウトできるようにログアウトボタンをどこかに配置する必要があります。

    私の場合はヘッダーにログアウトボタンを配置し、

    • ログインしていたらログアウトボタンを表示する
    • ログインしていなかったらログアウトボタンを非表示にする

    ということをしています。

    ログイン前なので、ヘッダーにログアウトボタンを表示しない。

    ログイン時の画面

    ログイン後なので、ヘッダーにログアウトボタンを表示する。

    ログイン後の画面


    そのため、ログアウトの機能とログインしているかの判定を行い、ログアウトボタンを表示する処理を追加します。

    // components/Header/Header.tsx
    
    import React, { useState, useEffect, useRef } from 'react';
    import { auth } from '../../../firebase';
    
    export const Header: React.VFC = () => {
      // ログアウトボタンをクリックしたらログインページへ遷移させるためにuseRouterを使用
      const router = useRouter();
    
      // ログインしているかの判定を入れるstate
      const [isLogin, setIsLogin] = useState(null);
    
      // マウント時に処理を行う
      useEffect(() => {
       // ログイン情報を取得
        const authProcess = auth.onAuthStateChanged((firebaseDatas) => {
          setIsLogin(firebaseDatas);
        });
        return () => authProcess();
      }, [isLogin]);
    
      // ログアウトイベント
      const handleLogOut = () => {
        router.push({
          pathname: `/`,
        });
        auth.signOut();
      };
    
      return (
        {isLogin ? (
          <button onClick={handleLogOut}>
            ログアウト
          </button>
        ) : null}
      )
    };


    一つづつ説明します。

    まずこちらの記述ですが、
    onAuthStateChangedメソッドで、ユーザーのログイン状態が変わるたびに、引数のfirebaseDatasにログイン情報が格納されます。

       // ログイン情報を取得
        const authProcess = auth.onAuthStateChanged((firebaseDatas) => {
          setIsLogin(firebaseDatas);
        });


    それをstateで管理して、以下のJSXでログアウトボタンの表示・非表示を制御しています。

      return (
          {/* ログイン情報があれば、ログアウトボタンを表示する */}
        {isLogin ? (
          <button onClick={handleLogOut}>
            ログアウト
          </button>
        ) : null}
      )

    ログアウトの実装

    次にログアウトの実装です。

    先程のログアウトボタンのonClickにhandleLogOutというイベントを設定しています。

    handleLogOutイベントの内容は以下です。

      // ログアウトイベント
      const handleLogOut = () => {
        router.push({
          pathname: `/`,
        });
        auth.signOut();
      };

    ログアウト自体はsignOutメソッドを呼び出すことで、ログアウトすることができます。

    ただ、ログアウトするとそのページにいた状態でログアウトされるので、ログイン後のページに居続けることになります。

    そのため、useRouterを使用して、ログアウトボタンをクリックしたらログインページへ遷移させてからログアウトをするということしています。

    長くなりましたが、これでログイン、ログアウトの実装は完了しました。

    次回

    ログイン、ログアウトの実装はできたのですが、今の状態でログインをすると、
    ログイン後のページが一瞬表示され、Googleログインへリダイレクトするという挙動になるかと思います。

    この対処法何かないかなと考えて一応無理やり対応できるようになりました。笑

    次回は、このログイン後のページが一瞬表示されないよう回避する、という対応を行いたいと思います。

    それでは次回もよろしく〜

記事をシェアする