🐥

Firebase Authenticationのログイン状態を管理する

2021/06/15に公開
3

はじめに

今回初めてfirebase Authenticationを使ってログイン機能を作りました。 
どのようにログイン状態を管理したのかを備忘録としてまとめます。
今回はログイン状態をContextでグローバルなStateとして管理しました。

環境

  • TypeScript
  • Next.js

実装

まずはContextを利用するためにProviderコンポーネントをつくります。

currentUserがログイン状態を表すstateです。
currentUserにユーザー情報が入っていればログインしていることを表し、値が入っていなければログインしていないことになります。

useEffectの中でログイン状態を確認します。
firebase AuthenticationではonAuthStateChanged関数でログインしているユーザーの情報を確認できます。ユーザーが存在していればstateにセットします。

このonAuthStateChanged関数ですがAuthオブジェクトの初期化に時間がかかるためonAuthStateChangedが呼び出されるまでに少し時間がかかります。
よってここではsignInCheckというstateでログイン状態を確認したかどうかを管理しました。
signInCheckがfalseの時、つまりログイン状態の確認ができていない間はローディング中であることを表示するLoadingコンポーネントを表示させることにしました。

Providerコンポーネントのコードはこのようになりました

auth/AuthProvider.tsx
import firebase from "firebase/app";
import { createContext, useEffect, useState, VFC, ReactNode } from "react";
import { auth, db } from "../firebase";
export type User = firebase.User;

type AuthContextProps = {
  currentUser: User | null | undefined;
  signInCheck: boolean;
};

const AuthContext = createContext<AuthContextProps>({
  currentUser: undefined,
  signInCheck: false,
});


const AuthProvider: VFC<Props> = ({ children }) => {
  const [currentUser, setCurrentUser] =
    useState<User | null | undefined>(undefined);

  const [signInCheck, setSignInCheck] = useState(false);
   
   // ログイン状態を確認する
  useEffect(() => {
    auth.onAuthStateChanged(async (user) => {
      if (user) {
        setCurrentUser(user);
        setSignInCheck(true);
      } else {
        setSignInCheck(true);
      }
    });
  });

  if (signInCheck) {
    return (
      <AuthContext.Provider value={{ currentUser, signInCheck }}>
        {children}
      </AuthContext.Provider>
    );
  } else {
      // ログイン確認中
    // 自分で作ったローディングコンポーネントをレンダリングする
    return <Loading />;
  }
};

export { AuthContext, AuthProvider };

そしてログイン状態を各コンポーネントから使えるようにするためにProviderコンポーネントで全体を囲みます。

pages/_app.tsx

const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {
  return (
    <>
        <AuthProvider>
            <Component {...pageProps} />
        </AuthProvider>
    </>
  );
};

ユーザー情報を使いたいページでは

  const {currentUser} = useContext(AuthContext)

のようにしてユーザー情報にアクセスできます。

Discussion

トモトモ
      if (user) {
        setCurrentUser(user);
        setSignInCheck(true);
      } else {
        setSignInCheck(true);
      }

setSignInCheckがどちらもtrueになっていますが、間違いでしょうか?

りんかりんか

signInCheckはログインを状態を確認したかを判別する値なので、最終的にはtrueになるため、どちらもtrueになるのが正しいと思います!

以下のコードの方が分かりやすいかもしれません!

// ログイン状態を確認する
useEffect(() => {
    auth.onAuthStateChanged(async (user) => {
      // ユーザーが存在する場合、ユーザー情報をstateにセットする
      if (user) {
        setCurrentUser(user);
      }

     // ログイン状態を確認したのでsignInCheckをtrueにする
     setSignInCheck(true)
    });
  });
トモトモ

ご回答ありがとうございます!
なるほどそういうことですか。