Firebaseのgoogle認証とcloud firestoreの使用 React

## はじめに

勉強用にfirebaseを使いました。
解説ではなく、備忘録です。

## firebaseの設定

firebaseにアクセス
https://console.firebase.google.com/

#### ①プロジェクトを作成
名前任意、googleアナリティクスはどちらでもOK
#### ②アプリの作成
プロジェクト押下するとアプリの追加ボタンがあるのでそこでアプリを追加（名前任意）
#### ③google認証の設定
Authentication押下
はじめる押下
Sign-in-methodタブになっていることを確認し、追加プロバイダ内の[Google]を押下
[有効にする]、サポートメールを設定し保存(プロジェクトの公開名はそのままでOK)
#### ④Cloud Firestoreの設定
Cloud Firestore押下
データベースの作成押下
本番モードチェックして、次へ
ローケーションを選択（asiaがつくところならどこでもいい気が）有効にするを押下
コレクションを追加を押下（DBみたいなもの）
コレクション名任意、ドキュメントIDは自動ID押下、フィールドがnullでOK
最後にルールタブを押下、allow read, write: if false;のfalseをtrueにする。
※これがないと書き込みが許可されず、保存の際にエラーになる。

## Reactに連携する設定

Firebaseの設定ボタン押下して[プロジェクトの設定]画面に遷移
スクロールするとマイアプリの設定があるのでそこのnpmにラジオボタンを選択し、
そこに書かれているインストールコマンドを実行（firebaseのモジュールのインストール）
```
npm install firebase
```
このコマンドの下に書かれているコードをコピーする。

ここからはVScode(エディター側)
src直下にfirebase.jsファイルを作成して
最後にfirebaseのコピーしたコードを貼り付ける。

そこから何個かimportや使えるようにインスタンス化させてexportするのを記述して以下のようにする。
```jsx
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAuth, GoogleAuthProvider } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
// TODO: Add SDKs for Firebase products that you want to use

// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: "アプリごとによって異なる",
  authDomain: "アプリごとによって異なる",
  projectId: "アプリごとによって異なる",
  storageBucket: "アプリごとによって異なる",
  messagingSenderId: "アプリごとによって異なる",
  appId: "アプリごとによって異なる"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
// 追加の記述
const auth = getAuth(app);
const provider = new GoogleAuthProvider();
const db = getFirestore(app);

export {auth, provider, db}; // 別ファイルで使えるようにexport
```
公式参照
https://firebase.google.com/docs/auth?hl=ja&_gl=1*dsgltp*_up*MQ..*_ga*MTU3MTk3MDYxMC4xNzMyMjg1NDQx*_ga_CW55HF8NVT*MTczMjI4NTQ0MS4xLjAuMTczMjI4NTQ0MS4wLjAuMA..

これで使う準備完了。

## Google認証の実装

成果物として
ボタン押下でポップアップがでて、google認証ができるようにする。
完成コード
```jsx
import React from "react";
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
import { auth, provider } from "../firebase";
import { useNavigate } from "react-router-dom";

const Login = ({setIsAuth}) => {
  const navigate =useNavigate();
  const loginInWithGoogle = ()=> {
    // googleでログイン
    signInWithPopup(auth, provider).then((result)=>{
      localStorage.setItem("isAuth", true); //localストレージに保存
      // 親のuseStateをtrueにする
      setIsAuth(true);
      navigate("/");
    });
  };

  return (
    <div>
      <p>ログインして始める</p>
      <button onClick={loginInWithGoogle}>Googleでログイン</button>
    </div>
  );
};

export default Login;

```

### それぞれの手順

最初にLogin.jsを作成して
bottonタグの中に onClic={loginInWithGoogle}を配置し、関数を発火させるトリガーを作成

関数の設定をする。
siginInWithPopupをタブ互換でimportする。（ポップアップで認証を行うためのfirebaseが用意した関数）
引数に前に設定してexportさせたauthとproviderをセットする。import忘れずに。
```
signInWithPopup(auth, provider).then((result)=>{}
```
こうなっていれば正解でこれでもう認証は可能になっている。

細かく説明しないがLoginコンポーネント呼び出し時にpropsでset関数（setAuth）を渡して
Authの状態をtrueにしている。
こうすることで初期値のfalseと認証後のtrueで表示の切り替えも可能になる。


#### ローカルストレージに認証の結果を保存する
localStorage.setItem("isAuth",true);
この記述でキーがisAuth、値にtrueが保存される。

デベロッパーツールのアプリケーションにて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832683/12386d5e-e929-a28a-f21b-b4c192ca15a2.png)

こうすることでリロードしてもローカルストレージにはこのデータが残り続ける。
useStateで認証は管理.する際にリロードすると消えてしまうのでこのローカルストレージを利用する。
const [isAuth, setIsAuth] = useState(localStorage.getItem("isAuth"));
リロードしてもisAuthの初期値にローカルストレージのデータを格納ができる。

## cloud firestoreの実装
成果物として
ボタン押下で指定のキーと値がcloud firestoreに保存ができるようにする。
完成コード
```jsx
import React, { useState } from "react";
import "./CreatePost.css";
import { addDoc, collection } from "firebase/firestore";
import {auth, db} from "../firebase";

const CreatePost = () => {
  const [title, setTitle] = useState();
  const [postText, setPostText] = useState();
  
  // ボタン押下で発火,addDocで指定のコレクションに保存する。
  const createPost = async() => {
    await addDoc(collection(db,"posts"),{
      title:title,
      postText:postText,
      author: {
        username: auth.currentUser.displayName,
        id: auth.currentUser.uid
      }
    }) 
  };
  
  return (
    <div className="createPostPage">
      <div className="postContainer">
        <h1>記事を投稿</h1>
        <div className="inputPost">
          <div>タイトル</div>
          <input
            type="text"
            placeholder="タイトルを記入する"
            onChange={(e) => setTitle(e.target.value)}
          />
        </div>
        <div className="inputPost">
          <div>投稿</div>
          <textarea
            placeholder="投稿内容を記入する"
            onChange={(e) => setPostText(e.target.value)}
          ></textarea>
        </div>
        <button className="postButton" onClick={createPost}>
          投稿する
        </button>
      </div>
    </div>
  );
};

export default CreatePost;
```

useStateを準備してonChangeイベントで入力文字をとれるようにする。（説明雑）
buttonにonClick={creatPost}をセットして発火準備。
#### createPostに保存するロジックを書いていく。
・まず非同期処理になるのでasyncとawaitを忘れないように注意。
・irestoreに保存するためにaddDocとcollectionをimportしておく。
・addDocの引数に１colloction,２保存内容をセット。
・colloctionの引数に１db,２firestore側で設定したコレクション名をセット。（上で任意設定している）

これだけでOK。
保存内容にset関数で値を取得したデータを飛ばせば、入力データが保存できるようになる。

## 最後に
こちらは全部自分で考えたわけでなく、Udemyなどで勉強して
忘れないようにアウトプットしたものになります。

次にこれをデプロイした際にうまく認証機能やfirestoreに保存できるか挑戦しようかと思っております。