はじめに
ReactにFirebaseを統合して認証機能を実装しました。そして今回は認証機能だけでなく、React Bootstrapのモーダルウィンドウを活用して、ログインとユーザー登録をスムーズに行えるようにしてみました。
完成イメージ
ユーザー登録からログインへ移動することもできます(逆も同じ)
デモページ
にて公開しています。
クラス図
Reactプロジェクトの作成
vscのコマンドラインでReactアプリケーションの新しいプロジェクトを作成します。例えば、Create React Appを使用して次のようにします。
npx create-react-app firebase-auth-app
cd firebase-auth-app
code . //フォルダを開く
React Bootstrapのセットアップ
React Bootstrapと標準のBootstrapをインストールします。
npm install react-bootstrap bootstrap
Firebaseプロジェクトのセットアップ
Firebaseコンソールにログインし、新しいプロジェクトを作成します。
プロジェクトを作成したら、Firebase Authenticationを有効にします(必要に応じてCloud Firestoreなどの他のFirebaseサービスも追加で有効にしておくと便利です)。
今回はメール/パスワードとGoogle認証を有効にしておきます。
Firebaseプロジェクトにアプリを登録し、自身のウェブアプリにFirebaseを追加します。
Firebase SDKの構成オブジェクトをReactに追加します。
npm install firebase
Firebaseコンソールから取得した設定を使用して、srcディレクトリ内にfirebase.jsファイルを作成します。
firebase.jsファイルに以下の内容を追加します。
// firebase.js
import { initializeApp } from "firebase/app";
import { GoogleAuthProvider, getAuth } from "firebase/auth";
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const provider = new GoogleAuthProvider();
export { auth, provider};
FirebaseのAPIキーやその他の機密情報を.env.localファイルに保存します。このファイルはGitなどのバージョン管理システムから除外されるため、機密情報が外部に公開される心配はありません。.env.localファイルは以下のようになります。
REACT_APP_FIREBASE_API_KEY=your-api-key
REACT_APP_FIREBASE_AUTH_DOMAIN=your-auth-domain
REACT_APP_FIREBASE_PROJECT_ID=your-project-id
REACT_APP_FIREBASE_STORAGE_BUCKET=your-storage-bucket
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=your-messaging-sender-id
REACT_APP_FIREBASE_APP_ID=your-app-id
ファイル構成
ログイン用モーダルウィンドウの作成
最初にGoogleのアイコンを使用するのでreact-iconsをインストールしておきます。
npm instal react-icons
srcディレクトリ内にcomponentsフォルダを作成し、その中にLoginModal.jsを作成します。
以下は、ログイン用のモーダルウィンドウを作成するコードです。
// LoginModal.jsx
import React, { useState } from 'react';
import { IoLogoGoogle } from "react-icons/io";
import { provider, auth } from '../firebase'; // Firebaseの認証関連の設定をインポート
import { signInWithPopup, signInWithEmailAndPassword } from 'firebase/auth'; // Firebaseの認証関連のメソッドをインポート
import { Button, Modal, Container, Form } from 'react-bootstrap'; // Bootstrapのコンポーネントをインポート
const LoginModal = ({ show, handleClose, showSignUpModal }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
// Googleアカウントを使用してログイン
const signInwithGoogle = async () => {
try {
await signInWithPopup(auth, provider);// FirebaseのsignInWithPopupメソッドを使用してGoogleアカウントでのサインインを試行
handleClose(); // モーダルを閉じる
} catch (error) {
console.error('Googleサインインエラー:', error.message); // エラーメッセージを表示
console.error(error); // エラーをコンソールに出力
}
};
// メールアドレスとパスワードでのログイン処理
const handleSubmit = async (event) => {
event.preventDefault();
try {
await signInWithEmailAndPassword(auth, email, password);
handleClose(); // モーダルを閉じる
} catch (error) {
alert('ログインエラー:', error.message);
console.error(error);
}
};
return (
<>
<Modal show={show} fullscreen='sm-down' centered onHide={handleClose}>
<Modal.Header closeButton>
</Modal.Header>
<Modal.Body className='m-4'>
<Container className='' >
<h3 className="text-center p-0" >ログイン</h3>
<hr className="m-4" />
<div className="text-center" >
<p className="mb-4">サインインするには:</p>
<div className='text-center' >
<IoLogoGoogle
style={{ color: '#1266f1', cursor: 'pointer' }}
className="mb-4"
onClick={signInwithGoogle}
size={26}
/>
</div>
<p className="mb-4">または:</p>
</div>
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-4" controlId="loginForm.email">
<Form.Label>メールアドレス</Form.Label>
<Form.Control
type="email"
placeholder="name@example.com"
autoFocus
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-4" controlId="loginForm.password">
<Form.Label>パスワード</Form.Label>
<Form.Control
type="password"
autoFocus
onChange={(e) => setPassword(e.target.value)}
/>
</Form.Group>
<div className="d-flex justify-content-end mb-5 ">
<a href="/password/reset" className='' >パスワードを忘れてしまった場合</a>
</div>
<button type="submit" className="btn btn-primary mb-5 w-100">サインイン</button>
</Form>
<div className="text-center">
<p>アカウントをお持ちではない方
<Button variant="link" onClick={showSignUpModal}>登録する</Button>
</p>
</div>
</Container>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
閉じる
</Button>
</Modal.Footer>
</Modal>
</>
);
}
export default LoginModal;
ユーザ登録用モーダルウィンドウの作成
ユーザ登録用のモーダルウィンドウも同様に作成します。
以下は、ユーザ登録用のモーダルウィンドウを作成するコードです。
// SignUpModal.jsx
import React, { useState } from 'react';
import { IoLogoGoogle } from "react-icons/io";
import { provider, auth } from '../firebase'; // Firebaseの認証関連の設定をインポート
import { signInWithPopup, createUserWithEmailAndPassword, updateProfile } from 'firebase/auth'; // Firebaseの認証関連のメソッドをインポート
import { Button, Modal, Container, Form } from 'react-bootstrap'; // Bootstrapのコンポーネントをインポート
const SignUpModal = ({ show, handleClose, showLoginModal }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [username, setUsername] = useState('');
// Googleアカウントでのサインイン処理
const signInwithGoogle = async () => {
try {
await signInWithPopup(auth, provider); // FirebaseのsignInWithPopupメソッドを使用してGoogleアカウントでのサインインを試行
handleClose(); // モーダルを閉じる
} catch (error) {
alert('Googleサインアップエラー:', error.message); // エラーメッセージを表示
console.error(error); // エラーをコンソールに出力
}
};
// メールアドレスとパスワードでのサインアップ処理
const handleSignup = async (event) => {
event.preventDefault();
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password); // FirebaseのcreateUserWithEmailAndPasswordメソッドを使用してサインアップを試行
const user = userCredential.user;
handleClose(); // モーダルを閉じる
// ユーザー名の設定
await updateProfile(user, {
displayName: username
});
} catch (error) {
alert('サインアップエラー:', error.message); // エラーメッセージを表示
console.error(error); // エラーをコンソールに出力
}
}
return (
<>
<Modal show={show} fullscreen='sm-down' centered onHide={handleClose}>
<Modal.Header closeButton>
</Modal.Header>
<Modal.Body className='m-4'>
<Container>
<h3 className="text-center p-0" >ユーザー登録</h3>
<hr className="m-4" />
<div className="text-center" >
<p className="mb-4">サインアップするには:</p>
<div className='text-center' >
<IoLogoGoogle
style={{ color: '#1266f1', fontSize: '25px', cursor: 'pointer' }}
className="mb-4"
onClick={signInwithGoogle}
/>
</div>
<p className="mb-4">または:</p>
</div>
<Form onSubmit={handleSignup} >
<Form.Group className="mb-3" controlId="signupForm.username">
<Form.Label>ユーザー名</Form.Label>
<Form.Control
type="text"
autoFocus
onChange={(e) => setUsername(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="signupForm.email">
<Form.Label>メールアドレス</Form.Label>
<Form.Control
type="email"
placeholder="name@example.com"
autoFocus
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Group>
<Form.Group className="mb-5" controlId="signupForm.password">
<Form.Label>パスワード</Form.Label>
<Form.Control
type="password"
autoFocus
onChange={(e) => setPassword(e.target.value)}
/>
</Form.Group>
<button type="submit" className="btn btn-primary mb-5 w-100">サインアップ</button>
</Form>
<div className="text-center" >
<p>
すでにアカウントをお持ちの方は
<Button variant="link" onClick={showLoginModal}>こちら</Button>
</p>
</div>
</Container>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
閉じる
</Button>
</Modal.Footer>
</Modal>
</>
);
}
export default SignUpModal;
モーダル
フォーム
アプリケーションの統合
最後に、Appコンポーネントでこれらのモーダルウィンドウを使用します。
ついでに認証後の処理とログアウトの処理も追加します。
import './App.css';
import React, { useState, useEffect } from 'react';
import LoginModal from './components/LoginModal';
import SignUpModal from './components/SignUpModal';
import { Button } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from './firebase';
function App() {
// ログインしているユーザーの情報を管理するステート
const [user, setUser] = useState(null);
// モーダルの表示状態を管理するステート
const [modals, setModals] = useState({ login: false, signUp: false });
// ログインモーダルを表示する処理
const handleLoginClick = () => {
setModals({ login: true, signUp: false });
};
// ユーザ登録モーダルを表示する処理
const handleSignUpClick = () => {
setModals({ login: false, signUp: true });
};
// モーダルを閉じる処理
const handleCloseModals = () => {
setModals({ login: false, signUp: false });
};
// Firebaseの認証状態が変化した際の処理
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user);
} else {
setUser(null);
}
});
return () => unsubscribe();
}, []);
// ログアウト処理
const handleLogout = () => {
auth.signOut();
// ログアウト後の処理を記述する(例:リダイレクトなど)
};
return (
<div className="App">
<div className='container '>
<div className='mt-5'>
{user ? (
// ログインしている場合の表示
<div>
<p>{user.email} でログイン中</p>
<Button variant="secondary" onClick={handleLogout}>ログアウト</Button>
</div>
) : (
// ログインしていない場合の表示
<>
<Button variant="primary" onClick={handleLoginClick}>ログイン</Button>
<Button variant="secondary" onClick={handleSignUpClick}>ユーザー登録</Button>
</>
)}
</div>
{/* ログイン用モーダル */}
<LoginModal show={modals.login} handleClose={handleCloseModals} showSignUpModal={handleSignUpClick} />
<SignUpModal show={modals.signUp} handleClose={handleCloseModals} showLoginModal={handleLoginClick} />
</div>
</div>
);
}
export default App;
テスト
ユーザー登録機能のテスト
まとめ
Firebase認証とReact Bootstrapを組み合わせて使用することで、ログインやユーザー登録などの認証機能を簡単に実装できました。
Firebaseの認証機能を利用することで、信頼性の高い認証システムを簡単に導入できるうえ、React Bootstrapを使用することで、UIデザインやレスポンシブデザインに関する考えをあまりすることなく、見栄えの良いUIを構築できました。
これにより、少ないコードと短時間で効率よく機能的なログイン・ユーザー登録フォームを作成することができます。
コードはGitHubでご覧いただけます:GitHubリンク
参考
Firebaseドキュメント
React Bootstrapドキュメント
Bootstrap5設置ガイド