Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created May 29, 2025 12:55
Show Gist options
  • Save sunmeat/dbf4b63ef9875b5de38758b5cc0dcacc to your computer and use it in GitHub Desktop.
Save sunmeat/dbf4b63ef9875b5de38758b5cc0dcacc to your computer and use it in GitHub Desktop.
useContext - авторизация на сайте
App.jsx:
import React, {createContext, useContext, useState} from 'react';
import './App.css';
// контекст аутентификации
const AuthContext = createContext();
// провайдер контекста аутентификации
function AuthProvider({children}) {
const [auth, setAuth] = useState({
isAuthenticated: false,
user: null,
role: 'гость'
});
// функция входа в систему
const login = (userData) => {
setAuth({
isAuthenticated: true,
user: userData,
role: userData.role || 'пользователь'
});
};
// функция регистрации
const register = (userData) => {
setAuth({
isAuthenticated: true,
user: userData,
role: userData.role || 'пользователь'
});
};
// функция входа как гость
const guestLogin = () => {
setAuth({
isAuthenticated: false,
user: {name: 'Гость'},
role: 'гость'
});
};
// функция выхода
const logout = () => {
setAuth({
isAuthenticated: false,
user: null,
role: 'гость'
});
};
return (
<AuthContext.Provider value={{auth, login, register, guestLogin, logout}}>
{children}
</AuthContext.Provider>
);
}
// кастомный хук useAuth упрощает доступ к контексту AuthContext, предоставляя компонентам удобный способ
// получения данных и методов аутентификации (auth, login, register, guestLogin, logout)
// вместо повторяющегося вызова useContext(AuthContext) в каждом компоненте, useAuth делает код чище,
// читабельнее и поддерживает единообразный интерфейс для работы с контекстом
const useAuth = () => useContext(AuthContext);
// главный компонент приложения
function App() {
const [screen, setScreen] = useState('auth');
const [theme, setTheme] = useState('light');
// переключение темы
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
// переход на экран контента
const goToContent = () => {
setScreen('content');
};
// переход на экран авторизации
const goToAuth = () => {
setScreen('auth');
};
// смена экранов зависит от состояния screen
return (
<AuthProvider>
<div className={`app ${theme}`}>
{screen === 'auth' ? (
<AuthScreen goToContent={goToContent} toggleTheme={toggleTheme}/>
) : (
<ContentScreen goToAuth={goToAuth} toggleTheme={toggleTheme}/>
)}
</div>
</AuthProvider>
);
}
// экран авторизации
function AuthScreen({goToContent, toggleTheme}) {
return (
<div className="auth-container">
<ThemeToggle toggleTheme={toggleTheme}/>
<AuthForm goToContent={goToContent}/>
<GuestButton goToContent={goToContent}/>
</div>
);
}
// компонент кнопки переключения темы
function ThemeToggle({toggleTheme}) {
return (
<button className="auth-button" onClick={toggleTheme}>
Сменить тему
</button>
);
}
// форма входа и регистрации
function AuthForm({goToContent}) {
const {login, register} = useAuth();
const [loginInput, setLoginInput] = useState('Alex');
const [password, setPassword] = useState('1234');
// обработчик входа
const handleLogin = (e) => {
e.preventDefault();
login({name: loginInput, role: 'пользователь'});
goToContent();
};
// обработчик регистрации
const handleRegister = (e) => {
e.preventDefault();
register({name: loginInput, role: 'пользователь'});
goToContent();
};
return (
<form className="auth-form">
<h2>Авторизация</h2>
<input
type="text"
placeholder="Логин"
value={loginInput}
onChange={(e) => setLoginInput(e.target.value)}
required
/>
<input
type="password"
placeholder="Пароль"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<div className="button-group">
<button className="auth-button" onClick={handleLogin}>
Вход
</button>
<button className="auth-button" onClick={handleRegister}>
Регистрация
</button>
</div>
</form>
);
}
// кнопка входа как гость
function GuestButton({goToContent}) {
const {guestLogin} = useAuth();
// обработчик входа как гость
const handleGuestLogin = () => {
guestLogin();
goToContent();
};
return (
<button className="auth-button guest" onClick={handleGuestLogin}>
Войти как гость
</button>
);
}
// экран контента
function ContentScreen({goToAuth, toggleTheme}) {
return (
<div className="content-container">
<ThemeToggle toggleTheme={toggleTheme}/>
<UserInfo/>
<Content/>
<Settings/>
<LogoutButton goToAuth={goToAuth}/>
</div>
);
}
// информация о пользователе
function UserInfo() {
const {auth} = useAuth();
return (
<div className="content-section">
<h2>Пользователь</h2>
<p>Имя: {auth.user?.name || 'Гость'}</p>
<p>Роль: {auth.role}</p>
<p>Статус: {auth.isAuthenticated ? 'Авторизован' : 'Не авторизован'}</p>
</div>
);
}
// контент
function Content() {
const {auth} = useAuth();
return (
<div className="content-section">
<h2>Контент</h2>
<p>Добро пожаловать, {auth.user?.name || 'Гость'}!</p>
</div>
);
}
// настройки
function Settings() {
const {auth} = useAuth();
return (
<div className="content-section">
<h2>Настройки</h2>
<p>{auth.isAuthenticated ? 'Настройки пользователя.' : 'Войдите для настроек.'}</p>
</div>
);
}
// кнопка выхода
function LogoutButton({goToAuth}) {
const {logout} = useAuth();
// обработчик выхода
const handleLogout = () => {
logout();
goToAuth();
};
return (
<button className="auth-button" onClick={handleLogout}>
Выйти
</button>
);
}
export default App;
================================================================================================================
App.css:
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Poppins:wght@300;400;600&display=swap');
:root {
--light-bg: linear-gradient(135deg, #ff00cc, #3333ff);
--light-text: #f0f0f0;
--light-accent: #ff00ff;
--light-glow: 0 0 10px rgba(255, 0, 204, 0.6);
--dark-bg: linear-gradient(135deg, #1a0033, #003366);
--dark-text: #e0e0ff;
--dark-accent: #ff33cc;
--dark-glow: 0 0 10px rgba(255, 51, 204, 0.7);
--transition: all 0.3s ease-in-out;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, #root {
height: 100%;
width: 100%;
}
body {
font-family: 'Poppins', sans-serif;
}
.app {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-size: 200% 200%;
animation: gradientShift 10s ease infinite;
}
@keyframes gradientShift {
0% {
background-position: 0 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
.light {
background: var(--light-bg);
color: var(--light-text);
}
.dark {
background: var(--dark-bg);
color: var(--dark-text);
}
.auth-container {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1.5rem;
max-width: 400px;
width: 100%;
background: rgba(255, 255, 255, 0.15);
border-radius: 15px;
backdrop-filter: blur(10px);
box-shadow: var(--light-glow);
}
.dark .auth-container {
box-shadow: var(--dark-glow);
}
.auth-form {
display: flex;
flex-direction: column;
gap: 0.8rem;
}
.auth-form h2 {
font-family: 'Orbitron', sans-serif;
font-size: 1.8rem;
font-weight: 700;
text-transform: uppercase;
text-shadow: var(--light-glow);
}
.dark .auth-form h2 {
text-shadow: var(--dark-glow);
}
.auth-form input {
padding: 10px;
border: none;
border-radius: 8px;
background: rgba(255, 255, 255, 0.2);
color: var(--light-text);
font-size: 0.9rem;
}
.dark .auth-form input {
color: var(--dark-text);
}
.auth-form input:focus {
outline: none;
box-shadow: var(--light-glow);
}
.dark .auth-form input:focus {
box-shadow: var(--dark-glow);
}
.button-group {
display: flex;
gap: 0.5rem;
}
.auth-button {
padding: 10px;
border: none;
border-radius: 8px;
cursor: pointer;
background: linear-gradient(45deg, #ff0066, #ffcc00);
color: #fff;
font-family: 'Poppins', sans-serif;
font-size: 0.9rem;
font-weight: 600;
transition: var(--transition);
box-shadow: var(--light-glow);
position: relative;
overflow: hidden;
}
.dark .auth-button {
background: linear-gradient(45deg, #cc00ff, #00ccff);
box-shadow: var(--dark-glow);
}
.auth-button:hover {
transform: scale(1.05);
box-shadow: 0 6px 15px rgba(255, 0, 204, 0.5);
}
.dark .auth-button:hover {
box-shadow: 0 6px 15px rgba(255, 51, 204, 0.6);
}
.auth-button::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: 0.4s;
}
.auth-button:hover::after {
left: 100%;
}
.auth-button.guest {
background: linear-gradient(45deg, #00ccff, #33ff33);
}
.dark .auth-button.guest {
background: linear-gradient(45deg, #33ffcc, #66ff33);
}
.content-container {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1.5rem;
max-width: 600px;
width: 100%;
background: rgba(255, 255, 255, 0.15);
border-radius: 15px;
backdrop-filter: blur(10px);
box-shadow: var(--light-glow);
}
.dark .content-container {
box-shadow: var(--dark-glow);
}
.content-section {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.content-section h2 {
font-family: 'Orbitron', sans-serif;
font-size: 1.6rem;
font-weight: 700;
text-shadow: var(--light-glow);
}
.dark .content-section h2 {
text-shadow: var(--dark-glow);
}
.content-section p {
font-size: 1rem;
line-height: 1.6;
font-weight: 300;
}
@media (max-width: 768px) {
.auth-container, .content-container {
padding: 1rem;
max-width: 90%;
}
.auth-form h2, .content-section h2 {
font-size: 1.5rem;
}
.auth-button {
padding: 8px;
font-size: 0.8rem;
}
}
@media (max-width: 480px) {
.auth-container, .content-container {
padding: 0.8rem;
}
.auth-form h2, .content-section h2 {
font-size: 1.4rem;
}
.auth-form input {
padding: 8px;
font-size: 0.8rem;
}
.auth-button {
padding: 6px;
font-size: 0.7rem;
}
.button-group {
flex-direction: column;
gap: 0.3rem;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment