masalibの日記

システム開発、運用と猫の写真ブログです

React Firebase入門 Authの拡張項目追加

FirebaseAuthの拡張項目追加と書いているのですが実際には Firestoreに項目を追加しているだけです。普通のアプリだと標準で用意されている項目だとユーザー情報として全然足りません。

この記事はReact Firebase入門シリーズです 1-1・ Firebase初期設定とFirebaseAuthのSignUp
1-2・ 「react-hook-form」を入れてみた
1-3・ AuthのSignUpの通信エラー対応
2 ・ FirebaseAuthのログイン処理
3 ・ FirebaseAuthのログイン認証とログアウト処理
4 ・ FirebaseAuthのパスワード初期化処理
5 ・ FirebaseAuthのメールアドレスの有効化
6 ・ FirebaseAuthのメールアドレスとパスワード変更
7 ・ FirebaseAuthの表示名変更
8 ・ FirebaseAuthの拡張項目追加 今ここ
8-1・ FirebaseStorageのファイルアップ:基礎
8-2・ FirebaseStorageのファイルアップ前に画像の切り抜き
8-3・ FirebaseStorageのファイルアップの移動 9-1・FirestoreのCRUD
9-2・Firestoreのデータ取得補足
9-3・Firestoreのページネーション処理
9-4・Firestoreのコレクション(テーブル)のJOIN
よかったら他の記事も見てください。

やりたい事

  • ユーザー情報をFirestore側にも保存する
  • 標準の項目以外も追加する

事前作業

FireStoreを使えるようにしないといけません 詳しくは下記の記事を参照してください

masalib.hatenablog.com

コレクションとしては以下と追加した状態にしてください

  • members(ユーザー情報)
  • departments(部署データ)

部署データはFirebaseのコンソールから以下のデータをいれてください。

departmentId departmentName
0001 システム開発
0002 コンシューマ事業部
0003 業務管理部

プログラム

修正した所だけ記載します。

もし全文を見たい人はこちらから参照してください Learn-Firebase/UpdateProfile.js at updateProfire_auth_ExpansionData · masalib/Learn-Firebase · GitHub

プログラム解説1

初期の読み込み時にuidをinitialStateを設定しています。

    currentUser.uid ? initialState = {...initialState,uid:currentUser.uid} : initialState = {...initialState,uid:""}
    const [departmentList, setDepartmentList] = useState([])
    const [expansionData, setExpansionData] = React.useState(false);      //拡張用のデータの有無
    const [expansionDocId, setExpansionDocId] = React.useState(false);      //拡張用のデータID

uidはSignUPした時にFirebaseが勝手に割り振ったユーザーIDです。基本的にはユニークになります

プログラム解説2

    useEffect(() => {
        async function fetchData() { 
            console.log("render")
            console.log(currentUser.uid)

            if (currentUser.uid){
                var query = await db.collection("members").where("uid", "==", currentUser.uid).get();
                console.log("query",query)
                console.log("query.empty",query.empty)

                if (!query.empty) {
                    //this.setState({
                    //    member: doc.data(),
                    //});

                    const result = query.docs.map(doc => doc.data());
                    console.log(result[0].departmentId)
                    dispatch({
                        type: "setDepartment",
                        payload: result[0].departmentId 
                    });
                    console.log("データ読み込み内部のrender")
                    setExpansionData(true)
                    setExpansionDocId(result[0].docId)

                } else {
                    console.log("データが存在しない")
                    setExpansionData(false)
                }
            }    
        }
        async function departmentData() { 
            const colRef = db.collection("departments")
            .orderBy('departmentId');

            const snapshots = await colRef.get();
            var docs = snapshots.docs.map(function (doc) {
                return doc.data();
            });
            setDepartmentList(docs)
        }
        departmentData();    //部署データ読み込み(セレクトボックスで使う方を先に読み込む)
        fetchData();
    },[currentUser.uid]);

ページの初期読み込み時に起動しています。そこでdepartmentsとmembersのデータを読み込みでいます。 membersにデータがない場合はquery.emptyがtrueになります。 そちらを利用してデータの有無を判定しています。

setExpansionData(true)
setExpansionDocId(result[0].docId)

updateで使用するために保存しています

プログラム解説3

{departmentList && <>
    <InputLabel className={classes.InputLabel} id="department-select-label">部署</InputLabel>
    <Select
        fullWidth
        labelId="department-select-label"
        id="department-select"
        value={state.departmentId}
        onChange={handleDepartmentChange}
        defaultValue={"0001"}
    >
        {
            departmentList.map((item,index) => {
                return (
                    <MenuItem key={item.departmentName} value={ item.departmentId }   >
                        {item.departmentName}:
                    </MenuItem>
                )
            })
        }
        <MenuItem key={"9999"} value={"9999"} >未所属</MenuItem>
    </Select>
</>
}

部署のセレクトボックスを追加して付属した部分を追加しています

//diaptch部分
    case "setDepartment":
    return {
        ...state,
        departmentId: action.payload + ""
    };

//関数部分
    const handleDepartmentChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
        dispatch({
            type: "setDepartment",
            payload: event.target.value
        });
    };

プログラム解説4

プロフィール更新時の処理に追加しています。本当はupdateにしたいのですが SignUP時のmembersのデータを作るためにはfunctionを設定しないといけないのでそちらはあとなので とりあえずcreateとupdateの処理をおこなっています

if (expansionData){
    let timestamp = firebase.firestore.FieldValue.serverTimestamp()
    promises.push(
        db.collection("members").doc(expansionDocId).update({
        uid: currentUser.uid,
        displayName: state.displayName,
        email: state.username,
        photoURL:state.photoURL,
        departmentId: state.departmentId,
        updatedAt: timestamp,
        })
    )
} else {
    let timestamp = firebase.firestore.FieldValue.serverTimestamp()
    const docId = db.collection("members").doc().id;

    promises.push(
        db.collection("members").doc(docId).set({
            docId: docId,
            uid: currentUser.uid,
            displayName: state.displayName,
            photoURL:state.photoURL,
            email: state.username,
            departmentId: state.departmentId,
            createdAt: timestamp,
            updatedAt: timestamp,
        })
    )    
}
  • db.collection("members").doc(expansionDocId).update({ の部分は取得する時と同じでwhereにしたかったのですが where().upateはないとおこられたのでdoc(id)形式にしています

  • chatとかで使う場合にはmembersにいれていた方が便利だと思ったので ユーザーの情報は基本的には保存しました。

結果

FireStoreの内容は以下になります

感想

  • 部署データIDをいう若干わかりにくい項目を追加しましたがテキストデータだろうと数字だろうと追加する方法は変わらないかと思う