React.Context とは?
propsで階層を順に下って値を引き渡すのではなく、下位階層すべてにプロパティを引き渡しちゃおうというもの。
コンテクストは各階層で手動でプロパティを下に渡すことなく、コンポーネントツリー内でデータを渡す方法を提供します。
https://ja.legacy.reactjs.org/docs/context.html
使い方
想定ケース
- 特定のページをログイン済みユーザーにだけ表示する。
- ログインしていない場合はログインページにリダイレクトさせる。
- ログイン成功したらCookieに情報を残しログイン済みとして扱う。
認証管理用コンポーネント
ログイン機能、ログアウト機能を提供。ログインしたらCookieに情報を残す。
AuthContext.jsx
import { setCookie } from '../utils/CookieUtil';
import React, { useContext} from 'react';
// 認証情報を共有するためのコンテキストを作成
const AuthContext = React.createContext();
// 認証コンテキストを簡単に利用するためのカスタムフック
export function useAuth() {
return useContext(AuthContext);
}
// 認証情報を提供するプロバイダーコンポーネント
export default function AuthProvider({ children }) {
// ユーザーログイン機能
async function login(id, password) {
let status = "200";
let message = "OK";
// ログイン処理(仮にtest/testで認証OKとする)
if (id === 'test' && password === 'test') {
// ログイン成功時の処理
// クッキーに認証情報を保存
setCookie('isAuth', 'true', 30);
} else {
status = "401";
message = "Unauthorized";
}
return { status, message };
}
// ユーザーログアウト機能
function logout() {
deleteCookie('isAuth');
return { status: "200", message: "OK" };
}
// コンテキストで提供する値
const value = {
login, // ログイン機能
logout // ログアウト機能
};
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
}
ルーター
先ほど作成したAuthContextを設置し、下位階層がログイン管理機能を使用できるように設定。
また、認証が必要なページ(/uop)へのアクセス、かつ、Cookieに情報がない場合は、ログインページ(/login)にリダイレクトする。
App.jsx
import { useEffect } from 'react';
import './App.css';
import { BrowserRouter, Route, Routes, useNavigate, useLocation } from 'react-router-dom';
import AuthContext from './contexts/AuthContext.jsx';
import UserOnlyPage from './components/UserOnlyPage.jsx';
import FreePage from './components/FreePage.jsx';
import Loginform from './components/Loginform.jsx';
import { getCookie } from './utils/CookieUtil';
function App() {
return (
<AuthContext>
<BrowserRouter>
<AuthHandler />
</BrowserRouter>
</AuthContext>
);
}
function AuthHandler() {
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const isAuth = getCookie('isAuth');
// 認証が必要なルートをチェック
if (location.pathname === '/uop' && isAuth !== 'true') {
navigate('/login'); // 認証が必要な場合はログインページにリダイレクト
}
}, [navigate, location]);
return (
<Routes>
<Route path='/uop' element={<UserOnlyPage />} />
<Route path='/free' element={<FreePage />} />
<Route path='/login' element={<Loginform />} />
</Routes>
);
}
export default App;
ログインフォーム
未認証の場合のリダイレクト先。
ログインに成功したらCookieに情報をセットされ、以降は認証済みとして扱われるようになる。
LoginForm.jsx
//ログインフォーム
import {React, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
// 認証関連のカスタムフックをインポート
import { useAuth } from '../contexts/AuthContext';
import {deleteCookie} from '../utils/CookieUtil';
export default function Loginform () {
const [id1, setId1] = useState('');
const [id2, setId2] = useState('');
const [password, setPassword] = useState('');
// 認証関連のカスタムフックを利用
const { login } = useAuth();
const navigate = useNavigate();
useEffect(() => {
// ログインページに遷移した際にクッキーを削除
deleteCookie('isAuth');
}, []);
const handleSubmit = async (e) => {
e.preventDefault();
try {
// ログイン処理
const res = await login(id1 + id2, password);
if (res.status === "200") {
navigate('/');
} else {
alert('ログインに失敗しました');
}
} catch (error) {
console.error('login error', error);
}
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor='id1'>氏名:</label>
<input
type='text'
id='id1'
value={id1}
onChange={(e) => setId1(e.target.value)}
/>
<input
type='text'
id='id2'
value={id2}
onChange={(e) => setId2(e.target.value)}
/>
<label htmlFor='password'>Password:</label>
<input
type='password'
id='password'
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type='submit'>Login</button>
</form>
);
}
その他:Cookie管理用util
Cookie作成、削除など機能提供用。
react-cookieを使ったほうがいいけど勉強のために自作。
CookieUtil.jsx
// クッキー設定関数
export const setCookie = (name, value, minutes) => {
const d = new Date();
d.setTime(d.getTime() + (minutes * 60 * 1000)); // 分単位で有効期限を設定
const expires = "expires=" + d.toUTCString();
document.cookie = `${name}=${value}; ${expires}; path=/`;
};
// クッキー取得関数
export const getCookie = (name) => {
const cname = name + "=";
const decodedCookie = decodeURIComponent(document.cookie);
const ca = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1);
if (c.indexOf(cname) === 0) return c.substring(cname.length, c.length);
}
return "";
};
// クッキー削除関数
export const deleteCookie = (name) => {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
};
参考:フォルダ階層
src
┗ components
┗ FreePage.jsx
┗ Loginform.jsx
┗ UserOnlyPage.jsx';
┗ contexts
┗ AuthContext.jsx
┗ utils
┗ CookieUtil.jsx
App.jsx