Тема: Створення системи автентифікації. Реалізація форм входу/реєстрації та захищених маршрутів (Protected Routes) за допомогою Context API.
Мета: Навчитися вирішувати проблему “prop drilling” за допомогою глобального керування станом (Context API); реалізувати логіку авторизації (вхід, реєстрація, вихід); опанувати патерн Higher-Order Component (HOC) для створення захищених маршрутів, що обмежують доступ неавторизованих користувачів до приватних сторінок додатку.
Технологічний стек: React, Vite, React Router v6, Context API, CSS Modules, Hooks (useState, useContext, useNavigate).
AuthContext та компонент-провайдер AuthProvider для зберігання глобального стану користувача.ProtectedRoute для захисту маршрутів.Для того, щоб стан авторизації (наприклад, ім’я користувача або статус логіну) був доступний у будь-якому компоненті без необхідності прокидати пропси через багато рівнів (prop drilling), ми використаємо Context API.
Створіть папку src/context та файл AuthContext.jsx.
Реалізуйте створення контексту та провайдера:
import { createContext, useState } from "react";
// Створення контексту
export const AuthContext = createContext();
// Компонент-провайдер
export const AuthProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [user, setUser] = useState(null);
const login = (userData) => {
setIsAuthenticated(true);
setUser(userData);
};
const logout = () => {
setIsAuthenticated(false);
setUser(null);
};
return (
<AuthContext.Provider value=>
{children}
</AuthContext.Provider>
);
};
Щоб контекст запрацював, необхідно огорнути ним головний компонент вашого додатку (бажано на рівні main.jsx або App.jsx).
У src/main.jsx:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import { AuthProvider } from "./context/AuthContext"; // Імпорт Провайдера
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<App />
</AuthProvider>
</BrowserRouter>
</React.StrictMode>,
);
В архітектурі SPA безпека та обмеження доступу реалізуються через патерн “HOC” (Higher-Order Component). Він перевіряє стан авторизації перед відображенням контенту.
Створіть файл src/components/hoc/ProtectedRoute.jsx:
import { Navigate, Outlet } from "react-router-dom";
import { useContext } from "react";
import { AuthContext } from "../../context/AuthContext";
const ProtectedRoute = ({ redirectPath = "/login", children }) => {
const { isAuthenticated } = useContext(AuthContext);
if (!isAuthenticated) {
// replace: true є критично важливим для чистоти історії браузера
return <Navigate to={redirectPath} replace />;
}
// Якщо компонент має children, рендеримо їх, інакше рендеримо Outlet для вкладених маршрутів
return children ? children : <Outlet />;
};
export default ProtectedRoute;
Використайте керовані компоненти для створення форми. При успішному вході викличте функцію login з контексту та перенаправте користувача.
Login.jsx:
import { useState, useContext } from "react";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../../context/AuthContext";
// Імпортуйте ваші Input та Button з попередніх лаб
const Login = () => {
const [email, setEmail] = useState("");
const { login } = useContext(AuthContext);
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
// Імітація перевірки даних (у Лаб №6 тут буде запит до API)
if (email) {
login({ email });
navigate("/profile", { replace: true });
}
};
return (
<form onSubmit={handleSubmit}>
<h2>Вхід в систему</h2>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<button type="submit">Увійти</button>
</form>
);
};
export default Login;
Оновіть ваш файл App.jsx, щоб захистити певні маршрути (наприклад, Профіль та налаштування).
import { Routes, Route } from "react-router-dom";
import MainLayout from "./components/templates/MainLayout/MainLayout";
import Home from "./pages/Home/Home";
import Login from "./pages/Login/Login";
import Profile from "./pages/Profile/Profile";
import ProtectedRoute from "./components/hoc/ProtectedRoute";
function App() {
return (
<Routes>
<Route path="/" element={<MainLayout />}>
<Route index element={<Home />} />
<Route path="login" element={<Login />} />
{/* Захищений маршрут */}
<Route element={<ProtectedRoute />}>
<Route path="profile/*" element={<Profile />} />
</Route>
</Route>
</Routes>
);
}
export default App;
replace: true у компоненті Navigate? (Поясніть вплив на стек історії браузера).lab_05.md винести фрагменти коду:
AuthContext.jsx.ProtectedRoute.jsx.lab_05.md дати вичерпні відповіді на контрольні запитання.