38
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Typescript×React×Hooksで会員管理①Firebase Authで認証基盤外出し

Last updated at Posted at 2020-01-15

業務で Typescript×React×Hooks を使ったフロントエンドのアプリケーションを開発しています。触り始めた当初はいろいろつまずきながら実装していて、自分が始める時にこんなサンプルアプリがあったら嬉しかったなというものを作ったので公開します。

本格的なアプリケーションにする骨組み(Boilerplate)としたく、長くなりそうなので全 3 回に分けます。

  1. Firebase Auth で認証基盤外出し
  2. Context でアプリの状態管理
  3. Formik と Yup でフォームバリデーション

利用している技術要素

  • Firebase Authentication
  • Typescript
  • React
  • React Hooks
  • Material UI

LT 資料

勉強会で Firebase Authentication の話をしたのでその時の資料を貼っておきます。

スクリーンショット 2020-01-02 19.08.30.png

スクリーンショット 2020-01-02 19.08.40.png

今回のサンプルアプリはこの図の ↔API という部分以外を実装しています。

ソースコード

  • メールアドレスでの認証に対応しています
  • 3 つの画面があります
    • 会員登録
    • ログイン
    • ホーム
  • ログイン状態に応じてリダイレクト/出し分けをします
    • ログインしているとホーム画面へリダイレクト
    • ログインしていないとログイン画面へリダイレクト
    • ホーム画面では Firebase から取得したユーザー情報を表示

デモ

会員登録して登録されたユーザー情報を閲覧。ログアウトして再度ログインしています。

demo.gif

動かし方

  1. github からソース取得
  2. Firebase でプロジェクトを作成し、Authentication の設定を行う
  3. 作成した Firebase プロジェクトから config 情報を取得し、./src/firebase.tsファイルを編集
  4. yarn startコマンドで React アプリを起動
  5. http://localhost:3000/ へアクセス

Firebase プロジェクトの作成と React アプリでキーになるポイントを簡単に解説します。

Firebase プロジェクトの作成

スクリーンショット 2020-01-02 18.14.10.png
  • 適当なプロジェクト名をつけて続行
スクリーンショット 2020-01-02 18.14.28.png
  • Google アナリティクスの設定は今回は関係無いのでどちらでも
スクリーンショット 2020-01-02 18.14.39.png
  • しばらくするとプロジェクトが出来上がる
スクリーンショット 2020-01-02 18.15.27.png
  • メニュー > Authentication > ログイン方法
  • メール / パスワード を有効にする
スクリーンショット 2020-01-02 18.15.57.png
  • 歯車アイコン > プロジェクトの設定 > 全般
  • マイアプリから Web アプリを追加
スクリーンショット 2020-01-02 18.16.31.png
  • 適当な名前をつけてアプリを登録
スクリーンショット 2020-01-02 18.16.43.png
  • React アプリから Firebase の API を叩くための接続情報が表示される
スクリーンショット 2020-01-02 18.17.00.png

React アプリのポイント解説

今回作成したアプリケーションでいくつかポイントになる部分があるので簡単に解説します。

  • github のコード をそのまま利用してもらえば動くので、Create React App コマンドによる React アプリ作成や各種ライブラリのインストール部分は端折っています
  • Firebase Authentication の各機能(signup や login)はかなり簡単に利用できます
  • React Hooks を利用しています。Hooks に慣れていなくてもなんとなくわかると思います

まず、Firebase の API を叩くために、先程 Firebase のコンソールで取得した接続情報を利用する部分です。

firebase.ts
import "firebase/auth";
import "firebase/firebase-firestore";

import firebase from "firebase";

// Firebaseの接続情報をconfigオブジェクトに保持
const config = {
  apiKey: "AIzaSyCZ8DipMr3pVI6JKR-SnhTlgGPNX9txF6E",
  authDomain: "test-7ef4b.firebaseapp.com",
  databaseURL: "https://test-7ef4b.firebaseio.com",
  projectId: "test-7ef4b",
  storageBucket: "test-7ef4b.appspot.com",
  messagingSenderId: "1044496636129",
  appId: "1:1044496636129:web:d21b7763773a509473ffa0"
};
firebase.initializeApp(config);

// Authサービスを作ってエクスポート。各画面でこれを利用する
const auth = firebase.auth();
export default auth;

続いて会員登録です。

Signup.tsx
import React, { Fragment, useEffect, useState } from "react";

import {
  Button,
  Container,
  FormControl,
  Grid,
  Link,
  TextField,
  Typography
} from "@material-ui/core";

// authサービスをインポート
import auth from "../firebase";

const Signup = (props: any) => {
  // ここではuseStateというHooksの機能を利用している
  // フォームに入力された値を保持する変数を宣言する形
  const [email, setEmail] = useState<string>("");
  const [password, setPassword] = useState<string>("");

  // useEffectもHooksの機能。ここではページがロードされたタイミングで
  // ログイン状態かどうかを判定するイベントを発動する
  useEffect(() => {
    auth.onAuthStateChanged(user => {
      // ログインしている場合、ホームへリダイレクト
      user && props.history.push("/");
    });
  }, []);

  return (
    <Fragment>
      <Container>
        <Grid container>
          <Grid item md={4}></Grid>
          <Grid item md={4}>
            <FormControl margin="normal" fullWidth>
              <TextField
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                name="email"
                label="E-mail"
                fullWidth
                variant="outlined"
                value={email}
                onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
                  setEmail(event.target.value);
                }}
              />
            </FormControl>
            <FormControl fullWidth>
              <TextField
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                name="password"
                label="Password"
                fullWidth
                variant="outlined"
                type="password"
                value={password}
                onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
                  setPassword(event.target.value);
                }}
              />
            </FormControl>
            <FormControl fullWidth>
              <Button
                fullWidth
                onClick={async () => {
                  try {
                    // Firebaseにユーザーを作成する
                    await auth.createUserWithEmailAndPassword(email, password);
                    // sendSignInLinkToEmail() を利用すると、メールアドレス認証のためのメールを送信することも可能
                    props.history.push("/login");
                  } catch (error) {
                    // ユーザー作成が失敗するとその内容をアラート表示
                    alert(error.message);
                  }
                }}
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
              >
                Sign up
              </Button>
              <Typography align="center">
                <Link href="/login">to login</Link>
              </Typography>
            </FormControl>
          </Grid>
          <Grid item md={4}></Grid>
        </Grid>
      </Container>
    </Fragment>
  );
};

export default Signup;

これだけでユーザーが作成できます。
ログイン画面も会員登録画面と似ているので、見ると何をしているかわかると思います。

最後にホーム画面です。ログイン状態だとこの画面にリダイレクトされます。

Home.tsx
import React, { Fragment, useEffect, useState } from "react";

import { Button, Container, Grid, Typography } from "@material-ui/core";

// authサービスをインポート
import auth from "../firebase";

const Home = (props: any) => {
  const [currentUser, setCurrentUser] = useState<null | object>(null);

  useEffect(() => {
    auth.onAuthStateChanged(user => {
      // ログイン状態の場合、currentUserというステート(変数)にAPIから取得したuser情報を格納
      // ログアウト状態の場合、ログインページへリダイレクト
      user ? setCurrentUser(user) : props.history.push("/login");
    });
  }, []);

  return (
    <Fragment>
      <Container>
        <Grid container style={{ marginTop: "1em" }}>
          <Grid item md={4}></Grid>
          <Grid item md={4}>
            <Typography>Here is the user information</Typography>
            <Typography
              variant="caption"
              style={{
                paddingTop: "2em",
                paddingBottom: "2em",
                whiteSpace: "pre"
              }}
            >
              // 格納されたuser情報を画面上に表示
              {currentUser && JSON.stringify(currentUser, null, 4)}
            </Typography>
            <Button
              fullWidth
              onClick={async event => {
                try {
                  // ログアウト処理。成功するとログイン画面へ遷移
                  await auth.signOut();
                  props.history.push("/login");
                } catch (error) {
                  alert(error.message);
                }
              }}
              style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
            >
              Logout
            </Button>
          </Grid>
          <Grid item md={4}></Grid>
        </Grid>
      </Container>
    </Fragment>
  );
};

export default Home;

次回

今回は紹介したものはわかりやすさのために最低限の実装しかしていません。
次回は Context を利用してアプリの状態管理ができるようにしていきます。

Typescript×React×Hooksで会員管理②Contextでアプリの状態管理

38
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?