Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает маршрутизация
Маршрутизация (Routing) - это основной механизм в современных веб-приложениях, который позволяет переходить между разными страницами без полной перезагрузки. Рассмотрю работу маршрутизации в различных контекстах.
1. Маршрутизация в браузере (History API)
Браузер предоставляет History API для управления историей переходов.
// История браузера
window.history.push('/page1'); // Перейти вперед
window.history.back(); // Вернуться назад
window.history.forward(); // Перейти вперед
window.history.go(-2); // На 2 страницы назад
// Более полезные методы
history.pushState(state, title, url);
history.replaceState(state, title, url);
// Пример
history.pushState(
{ page: 1 },
'Users Page',
'/users/1'
);
2. История событий (popstate)
Когда пользователь нажимает кнопку Back/Forward в браузере, срабатывает popstate событие.
window.addEventListener('popstate', (event) => {
console.log('Пользователь нажал Back/Forward');
console.log('State:', event.state);
// Обновить UI на основе нового URL
const path = window.location.pathname;
renderPage(path);
});
// Пример с состоянием
function navigateTo(path, data) {
history.pushState(data, '', path);
renderPage(path);
}
navigatedTo('/users/123', { userId: 123 });
3. Маршрутизация в Next.js (App Router)
Next.js 13+ использует новый App Router с файловой структурой.
// app/page.js - главная страница ("/")
export default function Home() {
return <h1>Главная</h1>;
}
// app/users/page.js - страница "/users"
export default function Users() {
return <h1>Пользователи</h1>;
}
// app/users/[id]/page.js - динамический роут "/users/:id"
export default function UserDetail({ params }) {
const { id } = params;
return <h1>Пользователь {id}</h1>;
}
// app/users/[...slug]/page.js - catch-all роут
export default function CatchAll({ params }) {
const { slug } = params; // массив сегментов
return <div>Catch all: {slug.join('/')}</div>;
}
4. Клиентская навигация в Next.js
import { useRouter } from 'next/navigation';
import Link from 'next/link';
export function Navigation() {
const router = useRouter();
// Способ 1: Link компонент (рекомендуется)
return (
<nav>
<Link href="/">Главная</Link>
<Link href="/users">Пользователи</Link>
<Link href="/users/123">Профиль</Link>
</nav>
);
}
export function UserAction() {
const router = useRouter();
// Способ 2: Программная навигация
const handleClick = () => {
// Перейти на новую страницу
router.push('/users/123');
// Заменить текущую запись в истории
router.replace('/home');
// Вернуться на предыдущую страницу
router.back();
// Перезагрузить текущую страницу
router.refresh();
// Перейти с префетчем
router.prefetch('/expensive-page');
};
return <button onClick={handleClick}>Действие</button>;
}
5. Фильтрация и Query параметры
import { useSearchParams, useRouter } from 'next/navigation';
export function FilterUsers() {
const router = useRouter();
const searchParams = useSearchParams();
// Получить query параметры
const role = searchParams.get('role');
const page = searchParams.get('page') || 1;
const handleFilter = (newRole) => {
// Создать новые параметры
const params = new URLSearchParams(searchParams.toString());
params.set('role', newRole);
params.set('page', '1');
// Обновить URL
router.push(`?${params.toString()}`);
};
return (
<div>
<button onClick={() => handleFilter('admin')}>Admin</button>
<button onClick={() => handleFilter('user')}>User</button>
<p>Текущая роль: {role}</p>
<p>Страница: {page}</p>
</div>
);
}
6. Матчинг маршрутов (Routing Matching)
Процесс определения, какой компонент показать для данного URL.
// Упрощенный алгоритм matcher
class Router {
constructor() {
this.routes = [];
}
addRoute(pattern, component) {
this.routes.push({ pattern, component });
}
// Преобразовать паттерн в регулярное выражение
patternToRegex(pattern) {
const regex = pattern
.replace(/\//g, '\\/')
.replace(/:([a-zA-Z]+)/g, '(?<$1>[^/]+)')
.replace(/\*\*/g, '.*');
return new RegExp(`^${regex}$`);
}
// Найти маршрут для URL
match(pathname) {
for (let route of this.routes) {
const regex = this.patternToRegex(route.pattern);
const match = pathname.match(regex);
if (match) {
return {
component: route.component,
params: match.groups || {}
};
}
}
return null; // 404
}
}
// Использование
const router = new Router();
router.addRoute('/', HomePage);
router.addRoute('/users', UsersPage);
router.addRoute('/users/:id', UserDetailPage);
const result = router.match('/users/123');
console.log(result);
// { component: UserDetailPage, params: { id: '123' } }
7. Создание кастомного маршрутизатора
class SimpleRouter {
constructor() {
this.routes = new Map();
this.currentPath = window.location.pathname;
}
// Регистрация маршрута
register(path, handler) {
this.routes.set(path, handler);
}
// Выполнить обработчик для маршрута
dispatch(path) {
const handler = this.routes.get(path);
if (handler) {
handler();
this.currentPath = path;
} else {
console.log('404: Route not found');
}
}
// Перейти на маршрут
navigate(path) {
history.pushState({ path }, '', path);
this.dispatch(path);
}
// Инициализировать слушатели
init() {
// При загрузке страницы
this.dispatch(this.currentPath);
// При нажатии Back/Forward
window.addEventListener('popstate', (e) => {
this.dispatch(window.location.pathname);
});
}
}
// Использование
const router = new SimpleRouter();
router.register('/', () => {
document.body.innerHTML = '<h1>Главная</h1>';
});
router.register('/about', () => {
document.body.innerHTML = '<h1>О сайте</h1>';
});
router.init();
// Навигация
router.navigate('/about');
router.navigate('/');
8. Охраняемые маршруты (Protected Routes)
// middleware.js (Next.js)
import { NextResponse } from 'next/server';
export function middleware(request) {
const token = request.cookies.get('auth_token');
const path = request.nextUrl.pathname;
// Проверить, защищен ли маршрут
const protectedPaths = ['/dashboard', '/profile', '/settings'];
if (protectedPaths.some(p => path.startsWith(p))) {
if (!token) {
// Перенаправить на login
return NextResponse.redirect(new URL('/login', request.url));
}
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*', '/profile/:path*']
};
Ключевые концепции
- Маршрутизация позволяет переходить между страницами без перезагрузки
- History API управляет историей браузера
- В Next.js маршруты основаны на файловой структуре
- Query параметры позволяют передавать состояние через URL
- Матчинг маршрутов - это процесс поиска нужного компонента
- Охраняемые маршруты требуют проверки прав доступа