Page.js — это микробиблиотека для маршрутизации на стороне клиента, позволяющая создавать SPA (Single Page Application) без необходимости полной перезагрузки страниц. Одной из ключевых концепций при работе с Page.js является изоляция контекстов. Контекст здесь означает объект, который передаётся в обработчики маршрутов и содержит состояние текущего перехода: параметры URL, хеш, путь, и дополнительные данные.
Каждый маршрут в Page.js получает объект контекста
(ctx), который автоматически создаётся при переходе.
Основные свойства этого объекта:
ctx.path — полный путь запроса, включая слэш и
параметры.ctx.params — объект с динамическими сегментами URL
(/user/:id → { id: '123' }).ctx.querystring — строка запроса после
?.ctx.hash — часть URL после #.ctx.state — объект для хранения пользовательских данных
между middleware и маршрутами.ctx.canonicalPath — путь без query и hash, полезен для
сравнения.Изоляция контекста означает, что каждое событие маршрутизации
получает новый объект ctx, полностью независимый
от предыдущих переходов. Это позволяет избежать нежелательного влияния
предыдущих состояний на текущий маршрут.
Page.js использует цепочку middleware для обработки маршрутов. Любой
middleware получает текущий контекст и функцию next,
которая передаёт управление следующему обработчику:
page((ctx, next) => {
ctx.state.startTime = Date.now();
next();
});
page('/user/:id', (ctx) => {
console.log(`Пользователь ${ctx.params.id}, время начала ${ctx.state.startTime}`);
});
ctx полностью уникален для каждой навигации.ctx.state служит контейнером для данных, которые нужны
только в рамках текущего маршрута.next() передаёт управление дальше, сохраняя
изоляцию контекста между middleware.Использование глобальных переменных для хранения состояния маршрутизации нарушает принцип изоляции контекста:
let globalData = {};
page('/user/:id', (ctx) => {
globalData.userId = ctx.params.id;
});
В этом случае, если произойдёт быстрый переход между маршрутами,
данные могут перезаписываться, вызывая непредсказуемое поведение.
Изоляция контекстов позволяет хранить состояние локально, в
ctx.state, исключая конкуренцию данных.
Изоляция контекста особенно важна при организации вложенных маршрутов. Например:
page('/dashboard', (ctx, next) => {
ctx.state.user = { id: 1, name: 'Admin' };
next();
});
page('/dashboard/settings', (ctx) => {
console.log(ctx.state.user.name); // 'Admin'
});
Каждый маршрут получает собственный объект ctx, но
middleware верхнего уровня может добавлять данные в
ctx.state, которые доступны дочерним маршрутам. Это
позволяет разграничивать глобальные и локальные данные,
сохраняя при этом изоляцию между переходами.
Page.js не хранит состояние между различными переходами по умолчанию. Для передачи данных используют:
page('/search', (ctx) => {
const query = new URLSearchParams(ctx.querystring).get('q');
console.log(query);
});
Session Storage / Local Storage — при необходимости сохранить данные вне контекста маршрута.
Сервис или менеджер состояния, если приложение использует централизованное хранение (например, Redux, Zustand). В этом случае важно различать состояние маршрута и глобальное состояние приложения.
При асинхронных вызовах нужно учитывать, что контекст может устареть при медленных ответах:
page('/data', async (ctx) => {
const id = ctx.params.id;
const response = await fetch(`/api/data/${id}`);
const data = await response.json();
console.log(data);
});
Если пользователь быстро переходит на другой маршрут,
ctx этого запроса остаётся неизменным, что гарантирует
корректную привязку данных к конкретному переходу. Использование
глобальных переменных в таких сценариях может привести к “утечкам”
данных между маршрутами.
ctx.state.Page.js автоматически создаёт новый контекст при всех типах переходов:
page('/path')Каждый из этих переходов получает независимый ctx, что
позволяет безопасно обрабатывать повторные маршруты и переходы в
короткие промежутки времени.