Свойство ctx.state

В Page.js объект ctx (context) представляет контекст текущего маршрута. Одной из ключевых возможностей является свойство ctx.state, которое служит для хранения произвольных данных, доступных на протяжении всего жизненного цикла обработки маршрута. Это мощный инструмент для передачи информации между middleware, обработчиками и представлениями.


Основные характеристики ctx.state

  1. Глобальность в пределах маршрута

    Данные, записанные в ctx.state, доступны всем функциям, которые обрабатывают текущий маршрут, включая цепочку middleware и конечный обработчик. При переходе на новый маршрут объект ctx.state создается заново, что исключает случайное распространение данных между маршрутами.

  2. Произвольная структура

    ctx.state — это обычный JavaScript-объект, поэтому можно хранить любые типы данных: строки, числа, объекты, функции. Это позволяет использовать его как хранилище временных данных, параметров маршрута или состояния интерфейса.

  3. Изоляция данных

    Каждое обращение к маршруту создает новый объект ctx.state, что обеспечивает изоляцию состояния между переходами. Например, данные, установленные при обработке /profile, не попадут в обработку /dashboard.


Создание и модификация ctx.state

page('/profile', (ctx, next) => {
    ctx.state.user = {
        id: 42,
        name: 'Иван'
    };
    next();
});

page('/profile', (ctx) => {
    console.log(ctx.state.user.name); // Иван
});

В примере выше первый middleware добавляет объект user в ctx.state. Второй обработчик маршрута получает доступ к этим данным напрямую через ctx.state.user.

Важно: любое изменение объекта ctx.state будет видно на всех последующих middleware текущего маршрута, поэтому можно использовать его для накопления и передачи информации.


Использование ctx.state для передачи данных в представления

Часто ctx.state применяется для подготовки данных, которые затем используются при рендеринге шаблонов или компонентов:

page('/dashboard', (ctx, next) => {
    ctx.state.stats = {
        visits: 1200,
        activeUsers: 58
    };
    next();
});

page('/dashboard', (ctx) => {
    renderDashboard(ctx.state.stats);
});

Здесь ctx.state.stats передается в функцию renderDashboard, которая отвечает за визуализацию данных. Такой подход позволяет отделить логику подготовки данных от рендеринга интерфейса.


Интеграция с middleware

Свойство ctx.state особенно удобно при использовании цепочки middleware, где необходимо пошагово добавлять данные:

page('/settings', authMiddleware, fetchSettings, renderSettings);

function authMiddleware(ctx, next) {
    ctx.state.isAuthenticated = true;
    next();
}

function fetchSettings(ctx, next) {
    ctx.state.settings = {
        theme: 'dark',
        notifications: true
    };
    next();
}

function renderSettings(ctx) {
    console.log(ctx.state.isAuthenticated); // true
    console.log(ctx.state.settings.theme);  // dark
}

Каждый middleware может дополнять ctx.state, не опасаясь перезаписать данные других функций, если используется уникальная структура ключей.


Советы по использованию ctx.state

  • Не хранить большие данные: ctx.state предназначен для передачи данных между middleware и обработчиками текущего маршрута, а не для постоянного хранения состояния приложения.
  • Использовать осмысленные ключи: Чтобы избежать конфликтов, давать ключам в ctx.state понятные и уникальные имена.
  • Не хранить DOM-элементы: Это может привести к утечкам памяти при повторных переходах по маршрутам.
  • Обновление и переиспользование: Можно модифицировать свойства объекта ctx.state на лету, но стоит помнить, что старые значения не сохраняются между переходами.

Примеры расширенного использования

Передача состояния между разными обработчиками

page('/product/:id', loadProduct, setPageTitle, renderProduct);

function loadProduct(ctx, next) {
    ctx.state.product = { id: ctx.params.id, name: 'Книга', price: 500 };
    next();
}

function setPageTitle(ctx, next) {
    ctx.state.title = `Товар: ${ctx.state.product.name}`;
    next();
}

function renderProduct(ctx) {
    document.title = ctx.state.title;
    console.log(ctx.state.product);
}

Использование ctx.state для флагов и условий

page('/admin', checkAdmin, renderAdmin);

function checkAdmin(ctx, next) {
    ctx.state.isAdmin = true; // флаг для интерфейса
    next();
}

function renderAdmin(ctx) {
    if (ctx.state.isAdmin) {
        console.log('Показать панель администратора');
    }
}

В таких сценариях ctx.state становится удобным инструментом для управления логикой маршрута, позволяя хранить как данные, так и флаги, влияющие на рендеринг и поведение приложения.


Свойство ctx.state является центральным элементом при организации маршрутизации в Page.js, позволяя аккуратно и безопасно хранить состояние маршрута, передавать данные между middleware и обработчиками, а также управлять логикой рендеринга на основе контекста.