Типы возвращаемых значений

Библиотека Universal Router предоставляет гибкий механизм маршрутизации для JavaScript-приложений, позволяя описывать маршруты в виде объектов с определёнными свойствами, включая path, action, children и другие. Одним из ключевых аспектов работы является возвращаемое значение функции action, которая выполняется при совпадении маршрута. Понимание типов возвращаемых значений позволяет строить сложные и масштабируемые маршруты, интегрировать асинхронные операции и управлять логикой навигации.


Прямые возвращаемые значения

Самый простой и распространённый вариант — непосредственное возвращение результата из action. Это может быть любой тип данных: строка, объект, число, HTML-шаблон и т.п.

import UniversalRouter from 'universal-router';

const routes = [
  {
    path: '/home',
    action: () => 'Главная страница'
  },
  {
    path: '/about',
    action: () => ({ title: 'О нас', content: 'Информация о компании' })
  }
];

const router = new UniversalRouter(routes);
router.resolve('/home').then(result => console.log(result));
// Выведет: "Главная страница"

Особенности:

  • Простая синхронная логика.
  • Возвращаемое значение сразу становится результатом маршрута.
  • Используется для статических страниц или простых ответов.

Возвращение промисов

Функция action может быть асинхронной, возвращая Promise. Это особенно полезно, когда требуется загрузка данных с сервера, чтение локального хранилища или выполнение других асинхронных операций перед рендерингом.

const routes = [
  {
    path: '/profile/:id',
    action: async ({ params }) => {
      const response = await fetch(`/api/user/${params.id}`);
      const data = await response.json();
      return data;
    }
  }
];

const router = new UniversalRouter(routes);
router.resolve('/profile/123').then(user => console.log(user));

Ключевые моменты:

  • Universal Router автоматически обрабатывает промисы, ожидая их разрешения перед возвратом результата.
  • Можно использовать async/await внутри action для удобства.
  • Позволяет строить маршруты с динамическими данными, не блокируя основной поток выполнения.

Делегирование через вложенные маршруты

Возвращаемое значение может быть результатом вызова вложенного маршрута, используя объект router.resolve внутри action. Такой подход полезен для маршрутов с вложенной структурой, когда часть логики маршрутизации делегируется дочернему маршруту.

const routes = [
  {
    path: '/dashboard',
    children: [
      {
        path: '/stats',
        action: () => 'Статистика'
      }
    ],
    action: (context, next) => next()
  }
];

const router = new UniversalRouter(routes);
router.resolve('/dashboard/stats').then(console.log);
// Выведет: "Статистика"

Особенности:

  • next() вызывает обработку дочерних маршрутов.
  • Если next() не вызывается, обработка останавливается на текущем маршруте.
  • Возвращаемое значение может быть как синхронным, так и асинхронным.

Возвращение функций

Функция action может возвращать другую функцию, которая затем вызывается в контексте рендеринга или дополнительной логики. Это позволяет строить ленивые вычисления и использовать паттерн “функция-генератор” для маршрутов.

const routes = [
  {
    path: '/lazy',
    action: () => () => 'Ленивая загрузка контента'
  }
];

router.resolve('/lazy').then(result => {
  console.log(result()); // Выведет: "Ленивая загрузка контента"
});

Преимущества:

  • Отложенное выполнение кода.
  • Удобно для больших приложений, где рендеринг требует дополнительных данных только при необходимости.

Возвращение null или undefined

Если action возвращает null или undefined, Universal Router интерпретирует это как отсутствие результата для текущего маршрута. В сочетании с next() это позволяет пропускать маршруты, передавая обработку выше по цепочке или к дочерним маршрутам.

const routes = [
  {
    path: '/optional',
    action: (context, next) => {
      if (!context.user) return null;
      return next();
    }
  }
];

Особенности:

  • Позволяет реализовать условные маршруты.
  • Используется для защиты маршрутов или динамических редиректов.
  • Не вызывает ошибок, если не найден результат.

Возвращение массивов и объектов с метаданными

Для сложных интерфейсов полезно возвращать структурированные объекты, которые содержат как данные, так и инструкции по отображению:

const routes = [
  {
    path: '/page',
    action: () => ({
      title: 'Страница',
      template: '<div>Контент</div>',
      scripts: ['/js/page.js']
    })
  }
];

Преимущества:

  • Упрощает интеграцию с системами шаблонов.
  • Позволяет передавать дополнительные данные, которые влияют на рендеринг.
  • Сохраняет согласованность данных и интерфейса.

Взаимодействие с редиректами

Возвращаемое значение может быть объектом с ключом redirect, что позволяет осуществлять перенаправление:

const routes = [
  {
    path: '/old',
    action: () => ({ redirect: '/new' })
  }
];
  • Universal Router не выполняет редирект автоматически, но возвращаемое значение удобно обрабатывать в коде приложения.
  • Позволяет централизованно управлять логикой навигации.

Обработка ошибок через возвращаемые значения

Возвращение ошибки из action реализуется через генерацию исключения, которое можно обрабатывать при вызове resolve:

const routes = [
  {
    path: '/secure',
    action: () => {
      throw new Error('Доступ запрещён');
    }
  }
];

router.resolve('/secure').catch(err => console.error(err.message));
// Выведет: "Доступ запрещён"
  • Позволяет строить безопасные маршруты.
  • Интегрируется с асинхронной обработкой промисов.
  • Можно комбинировать с next() для выбора альтернативного маршрута при ошибке.

Типы возвращаемых значений в Universal Router обеспечивают максимальную гибкость при построении маршрутов: от простых синхронных строк до асинхронных промисов, функций, объектов с метаданными и редиректов. Правильное использование этих возможностей позволяет строить масштабируемые и динамические приложения с централизованной логикой маршрутизации.