kurosame’s diary

日々やったことで気になったことをメモしてます

React + Firebase Authentication

以下の React で作ったアプリに Firebase Authentication を導入してみようと思う
Glossary

今回実装したコードはこちら
GitHub - kurosame/glossary: Glossary App using React


Firebase 側の設定

Firebase の Authentication からログイン方法を設定をクリック

f:id:kurosame-th:20190917170030p:plain

Google 認証を有効にして保存

f:id:kurosame-th:20190917170551p:plain


Firebase の初期設定

npm i firebase

Firebase のサービスを使う際は以下の設定が必要
下記の情報は Firebase からコピペできる
ちなみに隠してるけど、これらの情報は公開してもセキュアです

// firebase/config.ts
const config = {
  apiKey: '...',
  authDomain: '...',
  databaseURL: '...',
  projectId: '...',
  storageBucket: '...',
  messagingSenderId: '...'
}

export default config

Firebase を初期設定する

// firebase/index.ts
import firebase from 'firebase/app'
import 'firebase/auth'
import config from '@/firebase/config'

const firebaseApp = firebase.initializeApp(config)
export const auth = firebaseApp.auth()

ログイン画面を実装

ログインフローは全て FirebaseUI に任せる
FirebaseUI の React ラッパーが公式であるので、こちらを使って実装する

npm i react-firebaseui

以下は FirebaseUI の Config 設定
ログインの表示方法や認証後の遷移先、認証の種類を定義する

// firebase/ui-config.ts
import firebase from 'firebase/app'
import 'firebase/auth'

const uiConfig = {
  signInFlow: 'popup',
  signInSuccessUrl: '/',
  signInOptions: [firebase.auth.GoogleAuthProvider.PROVIDER_ID]
}

export default uiConfig

以下はログイン画面
Redux 周りの説明は省略します
componentDidMount ライフサイクル関数で Firebase の onAuthStateChanged オブサーバー関数を使って、user を取得している
user が取れればログイン済と判断し、null の場合は未ログインと判断している
そして、render 関数内で Store に保持している isLogin を使って、レンダリング有無を判断している
今回 isLogin を他のコンポーネントで使うため、Redux を使って Store に保持したが、他で使う用途が無ければ Local State で良い

また、firebase.auth().currentUserを使っても同様にログイン有無の判断ができるが、タイミングによってはログイン後でも null を返す場合がある
firebase.auth()が初期化されてないタイミングで currentUser を呼び出すと null になるらしい
推奨されている解決方法は onAuthStateChanged 関数のコールバックで user を受け取り、処理を行うことです
currentUser を使うのは、onAuthStateChanged 関数の処理の後が良いと思う

// Login.tsx
import React from 'react'
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'
import { connect } from 'react-redux'
import { bindActionCreators, Dispatch } from 'redux'
import uiConfig from '@/firebase/ui-config'
import { auth } from '@/firebase/index'
import { States } from '@/modules/states'
import { LoginActions, LoginState, setIsLogin } from '@/modules/login'

interface Props {
  state: { login: LoginState }
  actions: LoginActions
}

export class Login extends React.PureComponent<Props> {
  componentDidMount(): void {
    auth.onAuthStateChanged(user =>
      this.props.actions.setIsLogin({ isLogin: !!user })
    )


  // ログイン済であればnull、未ログインであればStyledFirebaseAuthを返す
  public render(): JSX.Element | null {
    if (this.props.state.login.isLogin) return null
    return <StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={auth} />
  }
}

export default connect(
  (states: States) => ({ state: { login: states.login } }),
  (dispatch: Dispatch) => ({
    actions: {
      setIsLogin: bindActionCreators(setIsLogin, dispatch)
    }
  })
)(Login)

動作確認

アプリを実行すると、以下のよく見る Google ログインが表示されるので、Google アカウントを使ってログインする

f:id:kurosame-th:20190918173255p:plain

ログイン後、Firebase コンソールのプロジェクトで Authentication タブを確認すると、ログインしたユーザが表示されていると思う
また、onAuthStateChanged 関数を使って、Store に保存した isLogin を見ると、ログイン済は true、未ログインは false が設定されていると思う