LoginSignup
0
1

More than 1 year has passed since last update.

【Firebase】Firebase Authentication メール&Google認証の実装(前編)【React】

Last updated at Posted at 2022-12-13

目指すところ

こんにちは
FirebaseAuthenticationをReactプロジェクトに実装を試みました
◆目指すところ
2つ認証方法でサインアップ(メール、Google)
◆本記事のオチ
メール認証…OK、Google認証…YET

タイトルの失敗談とは、取り組んでる間にエラーに見舞われ本目的(メールとGoogle認証)に夢半ばに挫けた結果となった為です
※FirebaseAuthenticationについては割愛
こういった経緯を綴ります

環境

Windows10
Firebase 9.15
React 18.2
Node.js 18.12.1

作業内容

基本参考にするサイト

まずはじめにこちらの2つのサイトを基本として手順をすすめた
このサイトの手順に従ってコードを書く
記事ごとコードが散らばってますが差分に注目していただければ幸いです

これから、コケたところをかいつまんで書きます

ディレクトリ構成

構成はRalacodeさんに準拠
[src]
├─[components]
| ├ Home.js
| ├ Login.js
| ├ Register.js
| ├ PrivateRoute.js
| └ PublicRoute.js
├─[context]
| └ AuthContext.js
├─App.js
├─App.css
├─firebase.js
└─Page404.js

まず、メール認証

元のコード

Login.js
import { useState } from 'react';
import { createUserWithEmailAndPassword } from "firebase/auth";
const SignUp = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const handleSubmit = (event) => {
    event.preventDefault();
const { email, password } = event.target.elements;
    auth.createUserWithEmailAndPassword(email.value, password.value);  };

上のサンプルコードをそのまま適用し、適当なメールアドレス(xxx@xxx.xxx)でFirebaseにサインアップを試みたが下記のエラーが返ってきた

Uncaught (in promise) TypeError: can't assign to property "_canInitEmulator" on "xxx@xxx.xxx"

こちらのサイトを参考にする
auth.createUserWithEmailAndPassword と書くとエラーが吐かれたと推測し、
createUserWithEmailAndPassword(auth, ...) に修正
import { auth } from '../firebase'; も追加すると正常に動作
修正コード

Login.js
import { useState } from 'react';
import { auth } from '../firebase';
import { createUserWithEmailAndPassword } from "firebase/auth";

const SignUp = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const handleSubmit = (event) => {
    event.preventDefault();
const { email, password } = event.target.elements;
    createUserWithEmailAndPassword(auth, email.value, password.value)
  };

React Routerエラー

そして、参照サイトのコードをコピペで進んでいた私に待ち構えていたのは、ReactRouterのエラーでした
元のコード

App.js
import SignUp from './components/SignUp';
import { AuthProvider } from './context/AuthContext';
import { BrowserRouter, Route } from 'react-router-dom';

function App() {
  return (
    <AuthProvider>
      <div style={{ margin: '2em' }}>
        <BrowserRouter>
          <Route path="/signup" component={SignUp} />
        </BrowserRouter>
      </div>
    </AuthProvider>
  );
}

export default App;

このあと出たエラーコード

<Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your Route in a Routes.

包めといわれても…
エラーコンソールをよく見ると

Please wrap your Route in a Routes.

からのー…あり?
エラーコードをググって以下のサイトにたどり着き修正していく

(変更前)

App.js
<BrowserRouter>
<Route path="/signup" conponent={SignUp} />
</BrowserRouter>

(変更後)

App.js
import { BrowserRouter, Route, Routes } from 'react-router-dom';

<BrowserRouter>
<Routes>
<Route path="/signup" element={<SignUp />} />
</Routes>
</BrowserRouter>

なるほど、RouteをRoutesで囲めということを理解
importにRoutesを追加
Routeの親にRoutesを追加(=Routesの子にRoute)
Routeの中、conponentのままではまだエラーが返ってきたので
elementを試してみる(componentからelementに変更)と正常に動作した

再度メールでFirebaseにサインインを試すとメール認証経由で、Firebase Authenticationにユーザー新規登録されていることも確認した(よし)

次に、アクセス制限設定

メール認証がクリア出来たのでアクセス制限設定に取り掛かる
また次のサイトを参考にしてとりあえずコピペで進めた

使われてないコマンドでコケる

その名の通り、Reactバージョンアップに伴いコマンド名が大々的に変わったようです
元のコード

Home.js
import { auth } from '../firebase';
import { useHistory } from 'react-router-dom';

const Home = () => {
  const history = useHistory();
  const handleLogout = () => {
    auth.signOut();
    history.push('/login');
  };
  return (
    <div>
      <h1>ホームページ</h1>
      <button onClick={handleLogout}>ログアウト</button>
    </div>
  );
};

export default Home;

そして、コンソールに次のエラーが返ってきた

export 'useHistory' (imported as 'useHistory') was not found in 'react-router-dom'

In react-router-dom v6 useHistory() is replaced by useNavigate().

これか。
修正コード

Home.js
import { auth } from '../firebase';
import { useNavigate } from 'react-router-dom';

const Home = () => {
  const navigate = useNavigate();
  const handleLogout = () => {
    auth.signOut();
    navigate('/login');
  };
  return (
    <div>
      <h1>ホームページ</h1>
      <button onClick={handleLogout}>ログアウト</button>
    </div>
  );
};

export default Home;

useHistoryをuseNavigateに置き換え、関係するところも修正、pushは消した
(Reactのバージョンによってコマンド表記・役割が変わることが判明。厄介だな。今後注意しよう)
この記事も参考にした

書き換えるとエラーは表示されなくなった

次に進む
元のコード+上記の修正分

Home.js
import { auth } from '../firebase';
import { useNavigate, Redirect } from 'react-router-dom';
import { useAuthContext } from '../context/AuthContext';
const Home = () => {
  const navigate = useNavigate();
  const { user } = useAuthContext();
  const handleLogout = () => {
    auth.signOut();
    navigate('/login');
  };

  if (!user) {
    return <Redirect to="/login" />;
  } else {
    return (
      <div>
        <h1>ホームページ</h1>
        <button onClick={handleLogout}>ログアウト</button>
      </div>
    );
  }
};

export default Home;

はい、出ましたエラーはこちら

export 'Redirect' (imported as 'Redirect') was not found in 'react-router-dom'

またこれか(Reactのバージョンごとのコマンド違い問題)
RedirectはNavigateに統合されたことを知り修正
修正コード

Home.js
import { auth } from '../firebase';
import { useNavigate, Navigate } from 'react-router-dom';
import { useAuthContext } from '../context/AuthContext';
const Home = () => {
  const navigate = useNavigate();
  const { user } = useAuthContext();
  const handleLogout = () => {
    auth.signOut();
    navigate('/login');
  };

  if (!user) {
    return <Navigate to="/login" />;
  } else {
    return (
      <div>
        <h1>ホームページ</h1>
        <button onClick={handleLogout}>ログアウト</button>
      </div>
    );
  }
};

export default Home;

PrivateRouteを設定

手順の通りコピペでファイルを作った

PrivateRoute.js
import { Route, Redirect } from 'react-router-dom';
import { useAuthContext } from '../context/AuthContext';
const PrivateRoute = ({ component: Component, ...rest }) => {
  const { user } = useAuthContext();
  return (
    <Route
      {...rest}
      render={(routeProps) => {
        return user ? <Component {...routeProps} /> : <Redirect to="/login" />;
      }}
    />
  );
};

export default PrivateRoute;

上記で出てきた話。RedirectをNavigateに書き換え(修正コードは省略)
App.jsファイルでRouteコンポーネントを作成したPrivateRouteに変更します。

App.js
import Home from './components/Home';
import SignUp from './components/SignUp';
import Login from './components/Login';
import { AuthProvider } from './context/AuthContext';
import { BrowserRouter, Route } from 'react-router-dom';
import PrivateRoute from './components/PrivateRoute';

function App() {
  return (
    <AuthProvider>
      <div style={{ margin: '2em' }}>
        <BrowserRouter>
          <PrivateRoute exact path="/" component={Home} />
          <Route path="/signup" component={SignUp} />
          <Route path="/login" component={Login} />
        </BrowserRouter>
      </div>
    </AuthProvider>
  );
}

export default App;

そうしてエラーコンソールには…

Uncaught Error: [PrivateRoute] is not a component. All component children of must be a or

エラーメッセージでいくつかググったがまだこのエラーは解決していない

ここで脱線します

ReactRouterエラーで試行錯誤していた矢先、突然、プロジェクトのゴキゲンが悪くなった。どうやらタイミング的にこの2つのコマンドを同時に実行してからだ(それが原因かは不明)

>npm start
>npm audit fix --force

localhostにサーブしてみて得られたエラーコードでぐぐって試してみたがなんとも直らず…
(エラーコードと参考サイトは省略)
なんだかんだでたどり着いたnode moduleがあやしい…これで直ってくれと天に祈る

直らなかった…

>npm start

確認にもう一度localhostにサーブしてみる。
→やはりエラー
こちらがエラー画面(画像)

>npm audit --force

エラーコードではなくエラーの中身に注目
パッケージが壊れてるっぽいので一旦削除してリビルドしてみる。

>npm r "エラーで表示された開発が終了されていたパッケージとか"

そうしてリビルドすること…
npm start を試してみる

>npm start

無事にlocalhostにサーブできました。
戻ってきた!

>npm run build

こちらも問題なく動いたので一安心です

さてここで大問題…
FirebaseAuthentication、Googleでのログイン実装がまだできてない
悲しい…
とりあえず本記事はここで筆を置きます
ここまで読んでいただきありがとうございました

後編に続く…!?
続きます…!!!!

FirebaseAuthentication公式ドキュメントの紹介

やっぱり公式ドキュメント最強説、ということで少し読んだ

反省+今後の課題

  • FirebaseAuthentication、Google認証の実装はできなかった
  • Node.jsの仕組みを理解する
  • Docker環境でReact+Firebase構築を学ぶ(将来用に)
  • FirebaseAuthentication、Google認証の実装する(次回投稿予定)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1