わしのlog

プログラミングとかバイクとか。

React + TypeScript + Firebase でユーザ登録_その2

はじめに

前回からの続きです。

今回は主にfirebaseの認証処理を書いていきます。

リポジトリ

サンプルのリポジトリはこちら。
github.com

Firebaseとの接続設定

お待たせしました。
いよいよFirebaseとの接続設定です。

まずはFirebaseの
『コンソール画面』→『Authentication』→右上にある『ウェブ設定』
をクリック。
すると、こんな画面が表示されるので
各値をメモなり覚えるなりしておきましょう。 f:id:devdaikichi:20190123120926p:plain

次に、src/配下にfirebaseというディレクトリを作り、それぞれのファイルを作成。
(実際にはディレクトリ名は何でもよい)

  • auth.ts
  • firebase.ts

firebase.tsに設定を書き込み。

import * as firebase from "firebase/app";
import "firebase/auth";

const config = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENSER_ID
};

firebase.initializeApp(config);

export default firebase;

以降のFirebase用の処理はfirebase.tsでexportしたものを使用していきます。

ここで、process.envという記述に注目。
これは環境変数から値を取得する為の記述です。
CRAでは、.envというファイルを作成して、変数名の頭にREACT_APP_と付けると
自動的に読んでくれるようになっています。
環境変数にapiKey等を設定したいので
プロジェクトrootに.envファイルを作成して、変数を定義しましょう。

REACT_APP_FIREBASE_API_KEY="your_apiKey"
REACT_APP_FIREBASE_AUTH_DOMAIN="your_authDomain"
REACT_APP_FIREBASE_DATABASE_URL="your_databaseURL"
REACT_APP_FIREBASE_PROJECT_ID="your_projectId"
REACT_APP_FIREBASE_STORAGE_BUCKET="your_storageBucket"
REACT_APP_FIREBASE_MESSAGING_SENDER_ID="your_messagingSenderId"

先程ウェブ設定画面で確認した値に対応する値を書いていきましょう。
ここまででアプリケーション側のfirebaseの接続設定が完了しました。

ユーザ登録処理

Firebaseへの登録処理

Firebaseへのユーザの登録処理を実装します。
auth.ts

import firebase from './firebase'

// Sign Up
export const signUp = (email: string, password: string) => {
  return firebase.auth().createUserWithEmailAndPassword(email, password)
}

と書きます。
exportされたfirebaseをimportして、EmailとPasswordを引数に登録処理を行っています。
他にもGoogle認証やTwitter認証等行えますが、今回は割愛します。

認証ページの処理

先程書いた登録処理を画面側からコールできるようにします。
SignUp.tsxに処理を書いていきます。

  // input要素が変更された時のハンドリング
  private handleChange = (event: any) => {
+    // エラー内容をクリア
+    this.setState({error: null})
+
+    if (event.target.name === "username") {
+      this.setState({username: event.target.value});
+    } else if (event.target.name === "email") {
+      this.setState({email: event.target.value});
+    } else if (event.target.name === "password") {
+      this.setState({password: event.target.value});
+    }
  };

見たままですが、input要素内部が変更された時の処理です。
変更される度に呼ばれ、エラーが表示されていたらクリアし
その後state内容を更新している形です。

+ import {signUp} from "./firebase/auth";

...

  // submitされた時の挙動
  private handleSubmit = async (event: any) => {
+    event.preventDefault();
+    //  // Firebaseにサインアップ
+      try {
+        // emailとpasswordで登録
+        const authUser = await signUp(this.state.data.email, this.state.data.password);
+      } catch (e) {
+        this.setState({
+          error: e
+       });
+      }
  };

こちらがFirebaseへのSignUp処理となります。
非同期処理で、importしたauth.tssignUp関数を読んでいます。
引数として渡すのは勿論state内のemailとpasswordです。

+ import TextField from "@material-ui/core/TextField/TextField";
...
  
  // エラーハンドリング
  private handleError = () => {
+    let errorMessage = "";
+    if (this.state.error.code === "auth/weak-password") {
+      errorMessage = "パスワードは6文字以上で入力して下さい。";
+    } else {
+      errorMessage = this.state.error.message;
+    }
+    return (
+      <TextField
+        error
+        fullWidth
+        id="filled-error"
+        label="Error"
+        value={errorMessage}
+        margin="normal"
+        variant="filled"
+      />
+    );
  };

こちらはエラーハンドリング処理です。
Firebaseからエラーが返ってきた場合にstate内のerrorにオブジェクトが入るので
その中のcodeを判定してエラーメッセージを設定しています。
現状はweak-passwordのみ、自分で定義したエラーメッセージを表示しています。
(他のエラーメッセージはそのまま出ちゃいます)

SignUp

ここまででSignUp処理の完成です。
npm start して実際に登録してみましょう。 f:id:devdaikichi:20190123140737p:plain
正しく登録されているか確認する場合は
FirebaseコンソールAuthenticationユーザタブに進んで見てみましょう。
f:id:devdaikichi:20190123140829p:plain
正しく登録されています。

FireStoreを使ったユーザ情報の登録

ここまででユーザ自体の登録はできましたが
肝心のユーザ情報(ここではユーザ名)が登録できていません。
そこで、FireStoreを使ってユーザ情報を登録してみましょう。
まずはFirebaseコンソールDatabaseに進み
データベースの作成ボタンを押下。
今回はテストなのでテストモードで開始にチェックを入れて有効にします。
f:id:devdaikichi:20190123141213p:plain
しばらく待つと、管理画面に移行します。
コレクションを追加を押下します。
今回はusersという名前でコレクションを作成します。
f:id:devdaikichi:20190123141359p:plain
次に、最初のドキュメントを追加します。
なんでもいいのですが、ドキュメントIDは空、
フィールドは以下で作りました。

  • username: string, 'root'
  • email: string, 'root@hoge.com'

f:id:devdaikichi:20190123141706p:plain

これでFireStoreが使えるようになりました。

次に、src/firebase配下にdb.tsファイルを作成。
以下の記述を行います。

import firebase from "./firebase";
import 'firebase/firestore';

/* ユーザ情報 */
interface User {
  uid: string,
  name: string,
  email: string
}

/* ユーザ情報の更新 */
export const updateUser = (user: User) => {
  firebase.firestore().collection('users').doc(user.uid).set({
    username: user.name,
    email: user.email
  });
};

これも見ての通りですが、importしたfirebase
firestore().collection('users')でFireStoreのusersコレクションを指定し
ドキュメントのキーとして、SignUp時に作成したユーザのuidを設定しています。
そして中身のフィールドに、受け取ったemailとusernameを設定しています。
大体直観的に使えるのではないでしょうか。

後はSignUp時に同時にユーザ情報を登録するだけですね。
SignUpページのSignUp関数に以下追記を行いましょう。

...

  const authUser = await signUp(this.state.email, this.state.password);
+  // ユーザ情報の更新
+  if (authUser.user) {
+      await updateUser({uid: authUser.user.uid, name: this.state.username, email: this.state.email});
+  }
    } catch (e) {

...

さっきと同じように、認証ページに飛んで登録してみます。
Authenticationで登録したユーザのuidと同じドキュメントで
入力したフィールドが保存されていたら成功です!
f:id:devdaikichi:20190123143710p:plain
お疲れ様でした。

まとめ

中々長くなってしまいました。
ですが簡単な登録処理だったらこんな感じかなと思います。
本当はここに

  • ログイン処理
  • 登録後の自動ログイン
  • ログイン状態を判定してリダイレクト
  • 登録時のValidate処理
  • ...etc

なんかも追加したかったのですが、本来の意図(とりあえずの実装)
から外れそうだったので割愛しました。
余力があればそのあたりも実装してアップデートしたいです。
それでは最後に参考文献を。

参考文献

qiita.com material-ui.com github.com qiita.com firebase.google.com masamichi.me



現場からは以上です。