概要
「React(TypeScript)× Firebaseで新規登録機能を実装した」の続編になります。
前回の記事では、新規登録機能の実装を行いましたが今回はログイン機能、アクセス制限を実装しました。
※Firebaseのver9.0で実装しました。
ログイン機能の追加
ログイン画面のマークアップを修正します。
新規登録する際は、新規登録画面が表示され、ログインする際は、ログイン画面が表示されるような仕様に変更します。
useStateを使って、ログインしているかしていないかの状態を管理します。
const [isLogin, setIsLogin] = useState(true);
以下のようなonClik
イベントが発火した際に、useStateのsetIsLogin
を使って状態を変更します。
クリックした際に、状態が反転するような仕様になっています。
isLogin
がtrue
の場合は、ログインしますか?というテキストが表示され、
isLogin
がfalse
の場合は、新規登録しますか?というテキストが表示されます。
<span
className={style.button}
onClick={() => setIsLogin(!isLogin)}
>
{isLogin ? "ログインしますか?" : "新規登録しますか?"}
</span>
上記のような状態管理を使用し、テキストの出し分けを動的に変更することが可能になります。
Auth.tsx
のreturn
内は、以下のようになります。
return (
<Fragment>
<Container>
<Grid container>
<Grid item md={4}></Grid>
<Grid item md={4}>
<h2>{isLogin ? "新規登録" : "ログイン"}</h2>
<Box component="form">
<TextField
style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
name="email"
label="E-mail"
fullWidth
variant="outlined"
value={email}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
handleChangeEmail(event);
}}
/>
<TextField
style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
name="password"
label="Password"
fullWidth
variant="outlined"
value={password}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
handleChangePassword(event);
}}
/>
<Button
fullWidth
style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
>
{isLogin ? "新規登録" : "ログイン"}
</Button>
<Grid container>
<Grid item>
<span
className={style.button}
onClick={() => setIsLogin(!isLogin)}
>
{isLogin ? "ログインしますか?" : "新規登録しますか?"}
</span>
</Grid>
</Grid>
</Box>
</Grid>
</Grid>
</Container>
</Fragment>
);
次は、実際にログインのロジック部分を作成します。
ログインのロジック部分は、新規登録の際のロジックとメソッドが違うだけでほとんど一緒です。
Firebaseの方で、signInWithEmailAndPassword
というログイン時に使用するメソッドが準備されているので使用します。
const Login = async () => {
await signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
console.log(userCredential);
navigate("/home");
})
.catch((error) => {
alert(error.message);
console.error(error);
});
};
上記のロジックを実際のButton部分に組み込みます。
isLogin
のstateを使用し、ログインする際には、Login()
が実行されるように、新規登録する際のRegister()
が実行されるように出し分けをします。
<Button
fullWidth
style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
onClick={isLogin ? Register : Login}
>
{isLogin ? "新規登録" : "ログイン"}
</Button>
これで、ログインと新規登録の機能の実装が完了しました。
※「パスワードを忘れましたか?」というテキストなんですが、後々パスワードを忘れた際の機能も実装しようと思います。
「ログインしますか?」をクリックすると、テキストが変更します。
以上でログイン機能は、実装完了です。
ただ一つ問題があり現在ログインすると、/home
にリダイレクトされるように設定していますが、http://localhost:3000/home と入力すると、ログイン後のページを閲覧することが可能になっています。
これでは、意味がないのでログインしているユーザーしかページを見れないようにするためのアクセス制限を実装しようと思います。
アクセス制限
アクセス制限をする前に、AuthContext.tsx
というファイルを作成します。react-router-dom
を使用し、ページ遷移を設定していきます。
react-router-dom
を使うため、react-router-dom
をインストールします。
$ npm install react-router-dom
AuthContext.tsx
でreact-router-dom
をimport
します。
import { Routes, Route } from "react-router-dom";
Routes
の中に、Route
を設定し、このpathのときはこのコンポーネントを表示するような設定をします。
今回は、/
の場合はAuth.tsx
を表示されるように設定し、/home
の場合はHome.tsx
が表示されるように設定します。
<Routes>
<Route path={`/`} element={<Auth />} />
<Route path={`/home`} element={<Home />} />
</Routes>
以下、全体のコードになります。
import React from "react";
import { Routes, Route } from "react-router-dom";
import Auth from "./Auth";
import Home from "./Home";
const AuthContext = () => {
return (
<Routes>
<Route path={`/`} element={<Auth />} />
<Route path={`/home`} element={<Home />} />
</Routes>
);
};
export default AuthContext;
これで、ルートの設定は完了です。
次は、本題のアクセス制限の実装になります。
アクセス制限では、まずユーザ-情報があるかないかを判断します。
App.tsx
にFirebaseと連携し、ユーザ-情報を取得しログインしているかしていないかを判断します。
ユーザー情報の状態管理を行うので、useStateで定義します。またFirebaseにUser
という型があるので、型宣言も行います。
import type { User } from "firebase/auth";
import { useState } from "react";
~省略~
type UserType = User | null;
~省略~
const [user, setUser] = useState<UserType>(null);
useEffect
を使用し、初回のレンダリングの際にFirebaseへユーザ-情報があるかを確認します。
Firebaseで、onAuthStateChanged
という現在ログインしているユーザーを管理するメソッドがあるので、onAuthStateChanged
を使用します。
import React, { useState, useEffect } from "react"; // useEffectの追加
import { auth } from "./firebase";
~省略~
useEffect(() => {
const authStateChanged = auth.onAuthStateChanged((user) => {
setUser(user);
});
return () => {
authStateChanged();
};
}, []);
あとは、useStateのuser
を使って、ログインしてる場合はAuthContext.tsx
に遷移し、どのコンポーネントへも遷移できるように設定します。
ログインしていない場合は、Auth.tsx
へ遷移し他ページを閲覧しようとしてもコンポーネントが表示されないように設定します。
return <>{user ? <AuthContext /> : <Auth />}</>;
以上で、アクセス制限の設定が完成です。
import React, { useState, useEffect } from "react";
import Auth from "./Auth";
import { auth } from "./firebase";
import type { User } from "firebase/auth";
import AuthContext from "./AuthContext";
type UserType = User | null;
const App = () => {
const [user, setUser] = useState<UserType>(null);
useEffect(() => {
const authStateChanged = auth.onAuthStateChanged((user) => {
setUser(user);
});
return () => {
authStateChanged();
};
}, []);
return <>{user ? <AuthContext /> : <Auth />}</>;
};
export default App;
まとめ
今回は、react-router-domのバージョン6で実装しました。最新のバージョンでの実装方法を記載している記事がなかなかないので、勉強になりました。
次は、投稿機能を実装したいと思います。
参考サイト