【Next.js+Firebase】
自身の勉強過程を
無理やり作品にしていく
Vol.3-2:ログイン時のチラつき回避

  • 【Next.js+Firebase】
    自身の勉強過程を無理やり作品にしていくVol.3-2:ログイン時のチラつき回避

    Firebase

    どうも!こんにちは!

    前回Firebase Authenticationを使用してログイン・ログアウトを実装しました。

    ただログインの際、
    Googleログインへリダイレクトする前に、ログイン後ページが一瞬表示される
    という問題があります。

    今回はこの挙動をどうやって回避したかを書いていきたいと思います。

    それではスタートです!

    ログイン時にログイン後ページが一瞬表示される

    以下のログインイベントの際に、router.push('/login')でログイン後ページへ遷移させていると思いますが、
    そこがGoolgeログインへリダイレクトよりも早く動いてしまうことで、ログイン後ページが一瞬表示されてしまうようです。

    // pages/index.tsx
    
    // ボタンクリック時のログインイベント
    const handleLogIn = () => {
      // インスタンスを生成
      const provider = new fbApp.auth.GoogleAuthProvider();
      // リダイレクトしてログインを行うため、signInWithRedirectを使用する
        auth.signInWithRedirect(provider);
        router.push('/login'); // このrouter.pushが早く動いてしまう。
      };

    んでsetTimeoutなどで、ずらしてrouter.pushすることでも、回避は可能だと思いますが、今回は別の方法でいきました。

    私の回避策

    router.pushが動いてしまいどうしようもないので、

    • ログインボタンクリック後はログイン後ページではなく、ローディングページに遷移させる
    • ログインが完了したらログイン後ページに遷移させる

    という方法で対策しました。笑

    具体的にどうやって実装していったのかを書いていきます。

    ローディングページの作成&遷移

    ログインボタンクリック後にローディングページに飛ばすわけですが、
    そのローディングページが必要ですので作成します。

    ローディングページ

    私はTailwind CSSを使用しているので、そこのPulseを拝借してローディングページを作成しました。

    // pages/loading/index.tsx
    
    import React from 'react';
    import { NextPage } from 'next';
    
    const Index: NextPage = () => {
      return (
        <div className="border border-gray-100 shadow rounded-md p-4 w-full">
          <div className="animate-pulse">
            <div className="h-10 w-5/12 mb-8 bg-gray-400 rounded"></div>
            <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
              <div className="h-8 bg-gray-400 rounded"></div>
              <div className="h-8 bg-gray-400 rounded"></div>
              <div className="h-8 bg-gray-400 rounded"></div>
              <div className="h-8 bg-gray-400 rounded"></div>
              <div className="h-8 bg-gray-400 rounded"></div>
              <div className="h-8 bg-gray-400 rounded"></div>
            </div>
          </div>
        </div>
      );
    };
    
    export default Index;

    そうすると、以下のようなローディングページが作成できます。

    ローディング画面

    ローディングページへ遷移させる

    ローディングページができれば、ログインボタンクリック後にまずこのローディングページに遷移させます。

    // pages/index.tsx
    
    // ボタンクリック時のログインイベント
    const handleLogIn = () => {
      // インスタンスを生成
      const provider = new fbApp.auth.GoogleAuthProvider();
      // リダイレクトしてログインを行うため、signInWithRedirectを使用する
        auth.signInWithRedirect(provider);
        router.push('/loading'); // 今回作成したloadingページへ遷移させる
      };

    こうすることで、ログインボタンをクリックしたら、
    ログイン後ページではなく、ローディングページに行くようになりました。

    ただこのままだとログインが完了しても、
    ローディングページにずっといつづけてしまいます。。

    そのため、ログインが完了したら、ログイン後ページに遷移という処理を行います。

    ログイン後ページに遷移させる

    ログイン後ページに遷移するとしても、

    1. ログインができるているか確認する
    2. ログインできていたら、ログイン後ページへ遷移させる

    この2つを行う必要があるので、こちらを実装していきます。

    ログインができるているか確認する

    前回headerコンポーネント内でログイン・ログアウトボタンの表示切り替え処理を入れていますので、
    今回もheaderコンポーネントに処理を追記します

    // 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);
        });
    
        if (isLogin !== null) { // ログインできていたらログイン後ページへ遷移させる
          const userDisplayName = isLogin.displayName;
          router.push({
            pathname: `/login`,
            query: { loginName: userDisplayName },
          });
        } else { // ログインできていなければ、ログインページへ遷移させる
            router.push({
              pathname: `/`,
            });
        }
        return () => authProcess();
      }, [isLogin]);
    
      // ログアウトイベント
      const handleLogOut = () => {
        router.push({
          pathname: `/`,
        });
        auth.signOut();
      };
    
      return (
        {isLogin ? (
          <button onClick={handleLogOut}>
            ログアウト
          </button>
        ) : null}
      )
    };

    useStateのisLoginで判定を行い、isLoginがnullでは無かったらログインできているので、ログイン後ページへ遷移。

    isLoginがnullだったらログインできていないので、ログインページへ遷移。

    という処理を追加しています。

    これでログインボタンクリック後に、一瞬ログイン後ページが表示されるのを回避できました。

    また、Firebaseのドキュメントにも書いてあったのですが、
    一度ログインしてもらえば、ログイン情報はどのページからも呼び出すことができるらしいので、
    「ログイン情報を用いて判定したい」となった場合、
    今回やったFirebase Authentication編の記述を参考にやってみてください。

    Firebase Authentication編はこれにて終了です!

    次回

    Firebaseを用いた認証でFacebookやyahooも実装したいですが、今そこまでできなそうなので、もし完成したらまた続編として書いていきたいと思います。

    次回は、FirebaseのCloud Firestoreというデーターベース機能を用いて、Todoリストを作成していきたいと思います!

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

記事をシェアする