64行で作成する、Firebaseを利用した認証&リダイレクト処理

# まえがき

![firebase-logo](https://firebase.google.com/downloads/brand-guidelines/PNG/logo-built_white.png)
Firebaseを使うと、ログイン認証機能を公式ドキュメントに従うことによって簡単に作成することが出来ます。
また、ログイン認証機能を作成した際はログイン状態によってリダイレクト処理を行うも合わせて行うことが多くあります。
しかし、この<font color="red">リダイレクト処理に関しては公式ドキュメントでは言及がありません。</font>
ですので、今回はReact.js+Firebaseでリダイレクト処理を作成します。

***必要な処理はFirebaseにすべて存在しているので、こちらも簡単に作成できます😆***

# リダイレクト処理

```JavaScript:hoc/authenticate.js

import { Component } from "react";
import { auth } from "../firebase/init";
import Loading from "../components/loading";

/**
 * 認証状態判定用HOC
 *
 * @param {*} WrappedComponent Reactコンポーネント
 * @param {boolean} needLogin ログイン要否 true:必須 false:不要
 * @param {*} redirectURL 状態不一致時リダイレクト先URL
 */
const Authenticate = (WrappedComponent, needLogin, redirectURL) =>
  class extends Component {
    constructor(props) {
      super(props);
      this.state = {
        isLogin: "",
        needLogin: needLogin,
        redirectURL: redirectURL
      };

      auth.onAuthStateChanged(user => {
        if (user) {
          this.setState({ isLogin: true });
        } else {
          this.setState({ isLogin: false });
        }
      });
    }
    render() {
      const { isLogin, needLogin, redirectURL } = this.state;
      if (isLogin === "") {
        return (
          <div>
            <Loading />
          </div>
        );
      } else if (isLogin) {
        if (needLogin) {
          return <WrappedComponent {...this.props} />;
        } else {
          location.href = redirectURL;
          return (
            <div>
              <Loading />
            </div>
          );
        }
      } else {
        if (needLogin) {
          location.href = redirectURL;
          return (
            <div>
              <Loading />
            </div>
          );
        } else {
          return <WrappedComponent {...this.props} />;
        }
      }
    }
  };

export default Authenticate;
```

## 解説

今回は共通の処理としてリダイレクト処理を利用したいため、[HOC](https://postd.cc/react-higher-order-components-in-depth/)を作成し、各画面でこれを呼び出す形とします。

firebaseの認証状態は[onAuthStateChanged](https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged)関数で判定することが出来ます。
これを使ってログイン状態を保持します。

```JavaScript
auth.onAuthStateChanged(user => {
    if (user) {
        this.setState({ isLogin: true });
    } else {
        this.setState({ isLogin: false });
    }
});
```

上記の状態に応じて、ローディングアイコン表示とリダイレクト処理を行います。

```JavaScript
render() {
    const { isLogin, needLogin, redirectURL } = this.state;
    if (isLogin === "") {
        return (
            <div>
                <Loading />
            </div>
        );
    } else if (isLogin) {
        if (needLogin) {
            return <WrappedComponent {...this.props} />;
        } else {
            location.href = redirectURL;
            return (
                <div>
                    <Loading />
                </div>
            );
        }
    } else {
        if (needLogin) {
            location.href = redirectURL;
            return (
                <div>
                    <Loading />
                </div>
            );
        } else {
            return <WrappedComponent {...this.props} />;
        }
    }
}
```

# リダイレクト処理利用画面

```Javascript:pages/top.js
import React, { Component } from "react";
import Authenticate from "../hoc/authenticate";

class Top extends Component {
  render() {
    return (
        <div>ログイン必須画面</div>
    );
  }
}
const needLogin = true;
const redirectURL = "/login";

export default Authenticate(Top, needLogin, redirectURL);
```

## 解説

リダイレクト処理を利用する側では、その画面がログイン必須かどうかを表す`needLogin`とリダイレクト先URLを表す`redirectURL`を設定し、`Authenticate'の引数に設定するのみです。

今回の例は、ログイン必須の画面ですので`needLogin = true;`、未ログイン状態ではログイン画面へリダイレクトさせたいため、`redirectURL = "/login";`としています。

```JavaScript
const needLogin = true;
const redirectURL = "/login";

export default Authenticate(Top, needLogin, redirectURL);
```

# まとめ

上記のようにリダイレクト処理をHOCとすることで、どこでも利用可能な共通処理とすることが出来ます。
また、ログイン状態の判定はFirebaseに用意されている[onAuthStateChanged](https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged)関数を利用して簡単に作成することが出来ます。
ログイン状態に応じたリダイレクト処理はほぼ必須の機能ですのでFirebase側にあって欲しい気もしますが、現状は存在していません。
ですので、今回のリダイレクト処理を活用出来るのであれば幸いです。