【Firebase】Firebase Authentication メール＆Google認証の実装（後編）【React】

## はじめに
ハマりそうだった原神放置中です、こんにちは。
早速以前投稿した記事の続きを書きたいと思います。
## 前回のおさらい
**◆前回の記事**

https://qiita.com/ryoko_yamazaki/items/acfa21be41eb716be15e

**◆前回の目的**
FirebaseAuthentication+Reactで
2種類のサインアップ（メール、Google）を実装する

**◆前回の結果**
* メール認証→OK
* Google認証→YET
* 作業中にnpmのトラブルに見舞われて中断
## 今回の目指すところ
* FirebaseAuthenticationにGoogle認証の実装

## 前提
### 環境・構成ディレクトリ
前回と変わりません
**◆環境**
Windows10
Firebase 9.15
React 18.2
Node.js 18.12.1

**◆ディレクトリ構成（Ralacodeさんに準拠）**
[src]
├─[components]
｜ ├ Home.js
｜ ├ Login.js
｜ ├ Register.js
｜ ├ PrivateRoute.js
｜ └ PublicRoute.js
├─[context]
｜ └ AuthContext.js
├─App.js
├─App.css
├─firebase.js
└─Page404.js
### 基本参考サイト（チュートリアル先）
この分かりやすい2つのサイトを見比べながら構築しました

https://ralacode.com/blog/post/react-firebase-authentication/

https://reffect.co.jp/react/react-firebase-auth#Google

### 他ちょこちょこみたサイト

https://www.sukerou.com/2022/04/2022react-router404.html

## 作業内容
### Google認証
前回の記事でメール認証はクリアできたのでGoogle認証にとりかかる。
まずしたこと
・Googleログイン画面だけを作る
・公式ドキュメントより下記を追加
```firebase.js
//追加
import { GoogleAuthProvider } from "firebase/auth";

const provider = new GoogleAuthProvider();
```
ログイン処理に、signInWithPopupではなく、signInWithRedirectを利用する
公式ドキュメントを参考にコードを書いてく

https://firebase.google.com/docs/auth/web/google-signin

```Login.js
import { provider } from '../firebase';
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import { getAuth, signInWithRedirect } from "firebase/auth";
import { getRedirectResult, GoogleAuthProvider } from "firebase/auth";

const auth = getAuth();
getRedirectResult(auth)
.then((result) => {
    // This gives you a Google Access Token. You can use it to access Google APIs.
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const token =
        credential.accessToken;

    // The signed-in user info.
    const user = result.user;
}).catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The AuthCredential type that was used.
    const credential = GoogleAuthProvider.credentialFromError(error);
    // ...
});

const Login = () => {
const navigate = useNavigate();
const [error, setError] = useState('');
const handleLogin = async (event) => {
    try {
    signInWithRedirect(auth, provider);
    navigate('/');
    } catch (error) {
    console.log(error);
    setError(error.message);
    }
};

return (
    <div>
    <h1>ログイン</h1>
    {error && <p style={{ color: 'red' }}>{error}</p>}
    <button onClick={handleLogin}>Googleログイン</button>
    </div>
);
};

export default Login;
```

とりあえずGoogleでログインができた。
ページ遷移もstateされていて問題ない模様。

これからGoogleログインで作ったページにメールアドレスログインフォームも追加する


```Login.js
import { provider } from '../firebase';
import { useNavigate } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { getAuth, signInWithRedirect } from "firebase/auth";
import { getRedirectResult, GoogleAuthProvider } from "firebase/auth";
import { Navigate, Link } from "react-router-dom";
import {signInWithEmailAndPassword, onAuthStateChanged } from "firebase/auth";

const auth = getAuth();
getRedirectResult(auth)
.then((result) => {
    // This gives you a Google Access Token. You can use it to access Google APIs.
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const token =
        credential.accessToken;

    // The signed-in user info.
    const user = result.user;
}).catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The AuthCredential type that was used.
    const credential = GoogleAuthProvider.credentialFromError(error);
    // ...
});


const Login = () => {
    const navigate = useNavigate();
    const [error, setError] = useState('');
    const handleLogin = async (e) => {
        try {
            signInWithRedirect(auth, provider);
            navigate('/');
        } catch (error) {
            console.log(error);
            setError(error.message);
        }
    };
    const [loginEmail, setLoginEmail] = useState("");
    const [loginPassword, setLoginPassword] = useState("");

    const handleSubmit = async (e) => {
            e.preventDefault();

            try {
                await signInWithEmailAndPassword(
                    auth,
                    loginEmail,
                    loginPassword
                );
            } catch (error) {
                alert("メールアドレスまたはパスワードが間違っています");
            }
        };

    const [user, setUser] = useState();

    useEffect(() => {
            onAuthStateChanged(auth, (currentUser) => {
                setUser(currentUser);
            });
        });

        return (
            <>
                <h1>ログイン</h1>
                <p>ログイン方法を選択してください</p>
                {error && <p style={{ color: 'red' }}>{error}</p>}
                <button onClick={handleLogin}>Googleログイン</button><br /><br />
                {user ? (
                    <Navigate to={`/`} />
                ) : (
                    <>
                        <form onSubmit={handleSubmit}>
                            <div>
                                <label>メールアドレス</label>
                                <input
                                    name="email"
                                    type="email"
                                    value={loginEmail}
                                    onChange={(e) => setLoginEmail(e.target.value)}
                                />
                            </div>
                            <div>
                                <label>パスワード</label>
                                <input
                                    name="password"
                                    type="password"
                                    value={loginPassword}
                                    onChange={(e) => setLoginPassword(e.target.value)}
                                />
                            </div>
                            <button>メールログイン</button>
                            <p>新規登録は<Link to={`/register/`}>こちら</Link></p>
                        </form>
                    </>
                )}
            </>
        );
};

export default Login;
```
</details>


```Home.js
import React, { useState, useEffect } from "react";
import { onAuthStateChanged, signOut } from "firebase/auth";
import { auth } from "../firebase.js";
import { useNavigate, Navigate } from "react-router-dom";

const Home = () => {
const [user, setUser] = useState("");

const [loading, setLoading] = useState(true);

useEffect(() => {
    onAuthStateChanged(auth, (currentUser) => {
    setUser(currentUser);
    setLoading(false);
    });
}, []);

const navigate = useNavigate();

const logout = async () => {
    await signOut(auth);
    navigate("/login/");
}

return (
    <>
    {!loading && (
        <>
        {!user ? (
            <Navigate to={`/login/`} />
        ) : (
            <>
            <h1>マイページ</h1>
            <p>{user?.email}</p>
            <button onClick={logout}>ログアウト</button>
            </>
        )}
        </>
    )}
    </>
);
};

export default Home;
```

### GoogleAuthentication使用時のちょくちょく出たエラーメッセージ
> Unable to process request due to missing initial state. This may happen if browser sessionStorage is inaccessible or accidentally cleared.

ググるとFirebaseサイドの問題と出てきたので一旦放置
## さいごに
これでFirebaseAuthenticationにメールとGoogle認証の実装ができた。
前編で取り組んでいたアクセス制限設定は次回以降に回します。
以上メモ代わりでした。ありがとうございました。