React（TypeScript）× Firebaseで新規登録機能を実装した

# 概要
最近のSaaSでは、必須機能と言っても過言ではない「新規登録機能」を実装いたいなと思い、FirebaseのFirebase Authenticationを使って新規登録機能を実装しました。
※Firebaseのver9.0で実装しました。

# React（TypeScript）プロジェクト作成
### ①プロジェクト作成

まずReact（TypeScript）のプロジェクトを作成します。

`npx create-react-app ここにプロジェクト名 --template typescript`

### ②必要なツールのインストール
プロジェクトで使うFirebaseの機能をインストールします。
`npm install --save firebase`

ログインページ完了後に、ページ遷移をするので`react-router-dom`もインストールします。
`npm install --save react-router-dom`

上記のインストールが完了したら、`npm start`で無事にプロジェクトが作成されていることを確認してください。

# Firebaseの初期設定
### ①プロジェクト作成
プロジェクトの作成が完了しましたら、Firebaseの初期設定を行います。
[Firebase](https://firebase.google.com/?hl=ja)ページで、画面中央にある「プロジェクト作成」をクリックしてください。
任意の名前でプロジェクト名を入力し、「続行」をクリックしてください。
![スクリーンショット 2022-06-06 17.15.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/7db4b2ae-08fd-ca34-cfb0-4404a5fa353c.png)


### ②Google アナリティクス（Firebase プロジェクト向け）
「Googleアナリティクスの設定について」を行うページに遷移します。今回は、ログイン機能の実装のみでGoogleアナリティクスは使用しないので、有効にするを外してください。
「プロジェクトを作成」をクリックし次に進んでください。

![スクリーンショット 2022-06-06 17.16.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/25424c57-b728-f648-de7b-7f98919ad4d6.png)


### ③認証情報を取得する
ReactとFirebaseを接続するために、認証情報が必要になるのでアプリを作成します。
画面中央にある5つアイコンが並んでおり、iosアプリ・Androidアプリ・ウェブアプリなど用途に合わせて設定できるようになっています。
今回は、ウェブでの使用になるのでウェブのアイコンをクリックしてください。
![login-app-概要-Firebase-コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/61e0bf81-fc26-9e38-b4b2-a3c8e3611bd6.png)

 
### ④アプリの登録
アプリのニックネームを入力し、「アプリを登録」をクリックしてください。

![スクリーンショット 2022-06-06 17.25.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/df597ebb-aa2a-cb6c-05a3-4c92d984da70.png)


### ⑤アプリ登録完了

アプリの登録を行うと、SDKが表示されます。
無事にアプリの作成が完了しましたので、「コンソール　に進む」をクリックしてください。

### ⑥使用する認証機能を有効にする
左メニューにある「Authentication」をクリックし、「Sign-in method」をクリックしてください。
![スクリーンショット 2022-06-06 18.06.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/96d9f5ee-0f60-8c04-8021-03a2ed78c45e.png)

「新しいプロバイダを追加」をクリックし、「メール/パスワード」を追加してください。
そして、「有効にする」にチェックを入れ、保存してください。



# ReactとFirebaseの連携
### ①.envの作成
先ほど作成したReactプロジェクトの`src`直下に、Firebaseへの認証情報を登録する`.env`を作成してください。
`.env`にapiやproject idの情報などを記載します。


### ②認証情報を登録する
以下の形式で、環境変数を`.env`に設定します。
```.env
REACT_APP_FIREBASE_API_KEY="ここにAPI_KEY"
REACT_APP_FIREBASE_AUTH_DOMAIN="ここにAUTH_DOMAIN"
REACT_APP_FIREBASE_PROJECT_ID="ここにPROJECT_ID"
REACT_APP_FIREBASE_STORAGE_BUCKET="ここにSTORAGE_BUCKET"
REACT_APP_FIREBASE_MESSAGE_SENDER_ID="ここにMESSAGE_SENDER_ID"
REACT_APP_FIREBASE_APP_ID="ここにAPP_ID"
```
Firebaseのプロジェクトの概要の右隣にある歯車マークをクリックします。
「プロジェクトの設定」をクリックし少し画面をスクロールすると、「SDK の設定と構成」という項目が表示されます。
apikeyなどの認証情報が記載されているので、`.env`に該当する情報を入力してください。

![スクリーンショット 2022-06-06 17.48.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/6661ba50-88df-aa7b-daf2-b1eafebf949c.png)


### ③`firebase.ts`の作成
Firebaseへの認証情報の設定ができましたら、`firebase.ts`でFirebaseへ接続を行います。
`firebase.ts`では、Firebaseへ接続するために必要な`firebase`をimportしているのと、ログイン機能で必要な`firebase/auth`をimportします。

```firebase.ts
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";

const firebaseApp = initializeApp({
  apiKey: process.env.REACT_APP_FIREBASE_APIKEY,
  authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
  appId: process.env.REACT_APP_FIREBASE_APP_ID,
});
export const storage = getStorage(firebaseApp);
export const auth = getAuth(firebaseApp);
export const db = getFirestore(firebaseApp);

```

# 新規登録ページの実装
新規登録機能を実装します。
CSSフレームワークのMaterial-UIをインストールします。

`npm install @mui/material @emotion/react @emotion/styled`

src直下に`Auth.tsx`を作成し、マークアップを作成します。

```Auth.tsx
import React, { Fragment, useState } from "react";
import { auth } from "./firebase";
import {
  createUserWithEmailAndPassword,
} from "firebase/auth";
import { useNavigate } from "react-router-dom"
import {
  Box,
  Button,
  Container,
  Grid,
  TextField,
} from "@material-ui/core";

const Auth: React.FC = () => {

　　　　//ここに新規登録機能のロジックを記載します。

  return (
    <Fragment>
      <Container>
        <Grid container>
        <Grid item md={4}></Grid>
          　　　<Grid item md={4}>
            <Grid item md={4}>
              ログイン
            </Grid>
            <Box component="form">
              <TextField
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                name="email"
                label="E-mail"
                fullWidth
                variant="outlined"
              />
              <TextField
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                name="password"
                label="Password"
                fullWidth
                variant="outlined"
                type="password"
              />
              <Button
                fullWidth
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
              >
                新規登録
              </Button>
            </Box>
          </Grid>
          <Grid item md={4}></Grid>
        </Grid>
      </Container>
    </Fragment>
  );
};

export default Auth;

```

# 新規登録のロジック実装

今回、新規登録で使用するemailとpasswordの状態を管理するように、useStateを定義します。
```Auth.tsx
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
```

emailとpasswordの`TextField`に、入力された値をuseStateで管理するようの関数を定義します。

```Auth.tsx
const handleChangeEmail = (event: React.ChangeEvent<HTMLInputElement>) => {
  setEmail(event.currentTarget.value);
};
const handleChangePassword = (event: React.ChangeEvent<HTMLInputElement>) => {
  setPassword(event.currentTarget.value);
};
```

定義した関数は、各TextFieldのonClickイベントで設定します。
```Auth.tsx
~~ 省略 ~~
<Box component="form">
	<TextField
		style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
		name="email"
		label="E-mail"
		fullWidth
		variant="outlined"
		value={email}
		onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
			handleChangeEmail(event);
		}}
	/>
	<TextField
		style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
		name="password"
		label="Password"
		fullWidth
		variant="outlined"
		type="password"
		value={password}
		onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
			handleChangePassword(event);
		}}
	/>
	<Button
		fullWidth
		style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
		onClick={Register}
	>
		新規登録
	</Button>
</Box>
~~ 省略 ~~
```

最後に、useStateで管理しているemailとpasswordの情報をFirebaseに登録する関数を定義します。
 Firebaseにある`createUserWithEmailAndPassword`という新規登録するメソットを使ってFirebaseにユーザー情報を登録します。
ユーザー登録が成功した際と、失敗した際の条件を記載します。
`.then `で、登録が成功した際に、react-router-domのuseNavigateを使って、指定のページにリダイレクトさせます。
今回は、例として`/post`というページにリダイレクトさせるように設定しています。
ここは、任意のページに遷移するように設定してください。
`.catch `で、登録が失敗した際に出るエラー文をアラートで表示させています。
Firebaseの仕様で、6文字以下でパスワードを設定しようとすると、登録できないのでエラーが返ってくるようになっています。
```Auth.tsx
~~ 省略 ~~
const navigate = useNavigate()

const Register = (event: any) => {
	event.preventDefault();
	createUserWithEmailAndPassword(auth, email, password)
	.then((userCredential) => {
		console.log(userCredential);
		navigate("/post")// 登録成功後のリダイレクトページを設定してください。
	})
	.catch((error) => {
		alert(error.message);
		console.error(error);
	});
};
~~ 省略 ~~
```

以上で、新規登録の実装ができました。
以下、全体のコードになります。
```Auth.tsx
import React, { Fragment, useState } from "react";
import { auth } from "./firebase";
import {
  createUserWithEmailAndPassword,
} from "firebase/auth";
import { useNavigate } from "react-router-dom"
import {
  Box,
  Button,
  Container,
  Grid,
  TextField,
} from "@material-ui/core";

const Auth: React.FC = () => {
  const [email, setEmail] = useState<string>("");
  const [password, setPassword] = useState<string>("");

  const navigate = useNavigate()

  const Register = async () => {
    await createUserWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        console.log(userCredential);
        navigate("/home");
      })
      .catch((error) => {
        alert(error.message);
        console.error(error);
      });
  };

  const handleChangeEmail = (event: React.ChangeEvent<HTMLInputElement>) => {
    setEmail(event.currentTarget.value);
  };
  const handleChangePassword = (event: React.ChangeEvent<HTMLInputElement>) => {
    setPassword(event.currentTarget.value);
  };

  return (
    <Fragment>
      <Container>
        <Grid container>
        <Grid item md={4}></Grid>
          <Grid item md={4}>
            <Grid item md={4}>
              ログイン
            </Grid>
            <Box component="form">
              <TextField
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                name="email"
                label="E-mail"
                fullWidth
                variant="outlined"
                value={email}
                onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
                  handleChangeEmail(event);
                }}
              />
              <TextField
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                name="password"
                label="Password"
                fullWidth
                variant="outlined"
                type="password"
                value={password}
                onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
                  handleChangePassword(event);
                }}
              />
              <Button
                fullWidth
                style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                onClick={Register}
              >
                新規登録
              </Button>
            </Box>
          </Grid>
          <Grid item md={4}></Grid>
        </Grid>
      </Container>
    </Fragment>
  );
};

export default Auth;
```

実際に、新規登録を行なってみます。
ダミーのメールアドレスと、パスワードを入力し新規登録をクリックします。
登録に成功すると、useNavigateで設定したページに遷移します。
![スクリーンショット 2022-06-21 10.11.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/868ce303-6c54-1ee0-7ffb-c9fe53795d6a.png)

Firebaseで新規登録ができているか確認してみます。
Firebaseのコンソール画面にログインしてください。AuthenticationのUsersに先ほど登録したユーザー情報が反映されていましたら登録完了になります。
![スクリーンショット 2022-06-21 10.13.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628122/a560fa7b-5d35-ce6b-2048-f2f846c68659.png)

# まとめ
Firebaseには、便利なメソットが多く準備されて簡単に新規登録機能を実装することができます。
Firebaseのバージョンで、ver8.0とver9.0でちょっとメソットの書き方が違ったりするのでどのバージョンで実装するのかを気をつけてください。
次回は、ログイン実装をしたいと思います。


# 参考記事

https://firebase.google.com/docs/auth/web/manage-users?hl=ja

https://zenn.dev/knaka0209/articles/9472e94612a6f0

https://qiita.com/shunnami/items/98a341d2ac20775241ad