👻
Reactの認証管理!useContext を使ったログイン状態の保持と管理
React で認証を管理する方法 (AuthContext + useAuth)
フロントエンドのアプリケーションでは、ユーザーの認証情報(ログイン状態)を管理する必要があります。
今回は、React の Context API を活用して、認証情報をグローバルに管理する方法を解説します。
1. 認証管理の仕組み
今回の実装では、以下のような仕組みを作ります。
- AuthContext を作成 → 認証情報をグローバルに管理
- AuthProvider で Context を提供 → アプリ全体で使えるようにする
- useAuth カスタムフックを作成 → 簡単に認証情報を取得・更新できるように
- ログイン情報を localStorage に保存 → ページをリロードしてもログイン状態を保持
- ProtectedRoute を作成 → ログインしていないとアクセスできないページを制御
2. AuthContext の作成
まずは、認証情報を管理する AuthContext
を作成します。
context/AuthContext.tsx
import React, { createContext, useContext, useEffect, useState } from "react";
type AuthContextType = {
isAuthenticated: boolean;
token: string | null;
login: (token: string) => void;
logout: () => void;
getToken: () => string | null;
};
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [token, setToken] = useState<string | null>(localStorage.getItem("token"));
useEffect(() => {
const storedToken = localStorage.getItem("token");
if (storedToken) {
setToken(storedToken);
}
}, []);
const login = (newToken: string) => {
localStorage.setItem("token", newToken);
setToken(newToken);
};
const logout = () => {
localStorage.removeItem("token");
setToken(null);
};
const getToken = () => token;
return (
<AuthContext.Provider value={{ isAuthenticated: !!token, token, login, logout, getToken }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
};
ポイント
-
AuthContext
を作成し、認証情報を保持する -
AuthProvider
でtoken
を管理し、ログイン・ログアウトを処理 -
useAuth
でcontext
を簡単に利用できるようにする
3. 認証を適用する (AuthProvider を使う)
次に、AuthProvider
をアプリ全体に適用します。
App.tsx
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Register from "./pages/Register";
import Dashboard from "./pages/Dashboard";
import ProtectedRoute from "./components/ProtectedRoute";
import { AuthProvider } from "./context/AuthContext";
const App: React.FC = () => {
return (
<AuthProvider>
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route element={<ProtectedRoute />}>
<Route path="/dashboard" element={<Dashboard />} />
</Route>
</Routes>
</BrowserRouter>
</AuthProvider>
);
};
export default App;
ポイント
-
AuthProvider
でアプリ全体をラップし、認証情報を提供 -
ProtectedRoute
を使って、認証が必要なページを制御
4. ログイン処理を実装
pages/Login.tsx
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import AuthCard from "../components/AuthCard";
import { useAuth } from "../context/AuthContext";
const Login: React.FC = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const navigate = useNavigate();
const { login } = useAuth();
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
try {
await fetch("http://localhost:9000/sanctum/csrf-cookie", {
credentials: "include",
});
const response = await fetch("http://localhost:9000/api/login", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
const data = await response.json();
if (response.ok) {
login(data.token);
navigate("/dashboard");
} else {
setError("ログインに失敗しました。");
}
} catch (err) {
setError("通信エラーが発生しました。");
}
};
return (
<AuthCard title="ログイン">
{error && <p className="text-red-500 text-sm mb-4">{error}</p>}
<form onSubmit={handleLogin} className="space-y-4">
<input type="email" placeholder="メール" value={email} onChange={(e) => setEmail(e.target.value)} />
<input type="password" placeholder="パスワード" value={password} onChange={(e) => setPassword(e.target.value)} />
<button type="submit">ログイン</button>
</form>
</AuthCard>
);
};
export default Login;
ポイント
-
sanctum/csrf-cookie
をリクエストして CSRF トークンを取得 - 成功したら
token
をlocalStorage
に保存し、ログイン状態を維持
まとめ
✅ AuthContext を作成し、認証情報をグローバルに管理
✅ ログイン状態を localStorage で保持し、リロード時も認証を維持
✅ ProtectedRoute でログイン必須ページを制御
これで React + Laravel API の認証管理 が簡単にできるようになりました! 🎉
Discussion