API reference

useContent()

Функция useContent() извлекает ближайшую информацию о содержимом для текущего маршрута. Возвращаемый объект включает в себя:

headings: ContentHeading[] | undefined;
menu: ContentMenu | undefined;

Массив headings содержит данные об элементах заголовка html <h1> - <h6> из файлов разметки.

Меню - это контекстные данные, объявленные в файлах menu.md. Дополнительную информацию о формате и местоположении файла см. в разделе определение файла меню.

useDocumentHead()

Функция useDocumentHead() используется для чтения метаданных заголовка документа.

useDocumentHead() извлекает объект DocumentHead, доступный только для чтения, который включает:

export interface DocumentHead {
  /**
   * Представляет собой элемент `<title>` документа.
   */
  readonly title?: string;
  /**
   * Используется для ручной установки метатегов в заголовке. Кроме того,
   * свойство `data` может быть использовано для вставки произвольных данных,
   * которые компонент `<head>` в дальнейшем может использовать для генерации тегов `<meta>`.
   */
  readonly meta?: readonly DocumentMeta[];
  /**
   * Используется для ручного добавления элементов `<link>` к `<head>`.
   */
  readonly links?: readonly DocumentLink[];
  /**
   * Используется для ручного добавления элементов `<style>` к `<head>`.
   */
  readonly styles?: readonly DocumentStyle[];
  /**
   * Произвольный объект, содержащий пользовательские данные. При создании `<head>` из
   * markdown-файлов, атрибуты frontmatter, которые не распознаются как известные
   * мета-имена (такие как title, description, author и т.д.), хранятся в этом свойстве.
   */
  readonly frontmatter?: Readonly<Record<string, any>>;
}

Все стартовые шаблоны включают компонент <RouterHead>, который отвечает за генерацию элемента <head> документа. Он использует функцию useDocumentHead() для получения текущих метаданных заголовка и вывода соответствующих элементов <meta>, <link>, <style> и <title>.

src/components/router-head/router-head.tsx
import { component$ } from '@builder.io/qwik';
import { useDocumentHead } from '@builder.io/qwik-city';
 
/**
 * Компонент RouterHead размещается внутри элемента `<head>` документа.
 */
export const RouterHead = component$(() => {
  const head = useDocumentHead();
 
  return (
    <>
      <title>{head.title}</title>
 
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
 
      {head.meta.map((m) => (
        <meta {...m} />
      ))}
 
      {head.links.map((l) => (
        <link {...l} />
      ))}
 
      {head.styles.map((s) => (
        <style {...s.props} dangerouslySetInnerHTML={s.style} />
      ))}
    </>
  );
});

useLocation()

Используйте функцию useLocation() для получения объекта RouteLocation текущего маршрута.

useLocation() позволяет разработчикам узнать текущий URL, параметры, а также то, осуществляет ли приложение в данный момент навигацию, что полезно для показа индикатора загрузки.

export interface RouteLocation {
  /**
   * Параметры маршрута, извлечённые из URL-адреса.
   */
  readonly params: Record<string, string>;
  /**
   * Текущий URL-адрес.
   */
  readonly url: URL;
  /**
   * True, если приложение в данный момент осуществляет навигацию.
   */
  readonly isNavigating: boolean;
}

Возвращаемое значение useLocation() аналогично объекту document.location, но его безопасно использовать на сервере, где нет глобального объекта location, и он реактивный, поэтому за его изменением можно следить.

Параметры маршрута

useLocation() извлекает параметры маршрута в объект params.

Предположим, что у вас есть:

  • Файл: src/routes/sku/[skuId]/index.tsx;
  • Пользователь переходит к: https://example.com/sku/1234;
  • Затем skuId можно получить через useLocation().params.skuId.
src/routes/sku/[skuId]/index.tsx
import { component$ } from '@builder.io/qwik';
import { useLocation } from '@builder.io/qwik-city';
 
export default component$(() => {
  const loc = useLocation();
 
  return (
    <>
      <h1>Артикул</h1>
      {loc.isNavigating && <p>Загрузка...</p>}
      <p>Путь: {loc.url.pathname}</p>
      <p>Код: {loc.params.skuId}</p>
    </>
  );
});

Приведённый выше код будет генерировать:

<h1>Артикул</h1>
<p>Путь: /sku/1234/</p>
<p>Код: 1234</p>

Обратите внимание, что useLocation - это API только для чтения, вы никогда не должны пытаться изменить значения возвращаемого объекта loc. Вместо этого обратитесь к API useNavigate().

useNavigate()

Функция useNavigate() позволяет программно переходить на следующую страницу, не требуя вмешательства пользователя и не вызывая перезагрузки всей страницы. Это API, используемый внутри компонента <Link> для поддержки навигации SPA.

Эта функция возвращает функцию nav(), которая может быть использована для "добавления" нового пути.

Также useNavigate можно использовать для SPA-обновления текущей страницы, вызывая функцию nav() без аргументов.

import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
 
export default component$(() => {
  const nav = useNavigate();
 
  return (
    <>
      <button
        onClick$={async () => {
          // SPA-навигация к `/dashboard`
          await nav('/dashboard');
        }}
      >
        Перейти к информационной панели
      </button>
 
      <button
        onClick$={async() => {
          // обновление страницы: вызов без аргументов
          await nav();
        }}
      >
        Обновить страницу
      </button>
    </>
  );
});

Этот компонент будет содержать кнопку, при нажатии на которую QwikCity будет переходить к /dashboard без перезагрузки страницы.

Обратите внимание, что для SEO и улучшения доступности лучше использовать компонент <Link> вместо useNavigate() для перехода на новую страницу после пользовательского взаимодействия.

routeLoader$()

Функция routeLoader$() используется для объявления нового серверного загрузчика для заданной страницы/конечной точки или макета. Qwik City выполнит все объявленные загрузчики для заданного маршрута. Компоненты Qwik могут позже ссылаться на загрузчики, импортируя их и вызывая возвращаемую пользовательскую функцию для получения данных.

import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useGetTime = routeLoader$(async () => {
  return { time: new Date() }
});
export default component$(() => {
  const signal = useGetTime(); // Signal<{time: Date}>
  console.log('Date': signal.value.time);
  return (
    <div>{signal.value.time.toISOString()}</div>
  )
});

Для получения дополнительной информации обратитесь к разделу Загрузчики маршрута.

routeAction$()

Функция routeAction$() используется для объявления нового серверного действия на данной странице/конечной точке или макете. QwikCity будет выполнять только вызванное после некоторого взаимодействия с пользователем действие (например, нажатие кнопки или отправка формы).

Для получения дополнительной информации обратитесь к разделу Действия сервера.

<QwikCityProvider>

Компонент QwikCityProvider инициализирует QwikCity в существующем документе, предоставляя необходимый контекст для работы QwikCity, такой как useContent() и useLocation().

Этот компонент обычно находится в самом корне вашего приложения, в большинстве интеграций вы найдёте его в файле src/root.tsx:

src/root.tsx
export default component$(() => {
  /**
   * Корень сайта QwikCity всегда начинается с компонента <QwikCityProvider>,
   * сразу за ним следуют <head> и <body> документа.
   *
   * Не удаляйте элементы `<head>` и `<body>`.
   */
 
  return (
    <QwikCityProvider>
      <head>
        <meta charSet="utf-8" />
        <link rel="manifest" href="/manifest.json" />
        <RouterHead />
      </head>
      <body lang="en">
        <RouterOutlet />
        <ServiceWorkerRegister />
      </body>
    </QwikCityProvider>
  );
});

QwikCityProvider не рендерит ни один элемент DOM, даже не совпадающий маршрут, он просто инициализирует логику ядра Qwik City, по этой причине его не следует использовать более одного раза в одном и том же приложении.

<QwikCityMockProvider>

Компонент QwikCityMockProvider инициализирует контекст Qwik City для тестирования. Он обеспечивает необходимый контекст для работы кода Qwik City в тестах, например useContent(). И наоборот, для useNavigate(), <Link>, useLocation() и так далее. Рекомендуется использовать его в тестовых файлах.

QwikCityMockProvider не отображает никаких элементов DOM, что означает, что он не будет виден в снэпшотах.

Если вы ищете общий пример того, как интегрировать vitest в ваш Qwik, посмотрите документацию по интеграции vitest.

src/components/card.spec.tsx
import { createDOM } from '@builder.io/qwik/testing';
import { QwikCityMockProvider } from '@builder.io/qwik-city';
import { test, expect } from 'vitest';
 
// Компонент с двумя свойствами. Внутри использует <Link>. Опущено для краткости.
import { Card } from './card';
 
const cases = [
  {text: 'qwik', link:'https://qwik.builder.io/docs/api'},
  {text: 'vitest', link: 'https://vitest.dev'}
];
 
test.each(cases)('должен отрисовывать карту с %s %s', async ({text, link}) => {
  const { screen, render } = await createDOM();
  await render(
    <QwikCityMockProvider>
      <Card text={text} link={link} />
    </QwikCityMockProvider>,
  );
  expect(screen.innerHTML).toMatchSnapshot();
});

<RouterOutlet>

Компонент RouterOutlet отвечает за рендер совпадающего в данный момент маршрута, он использует под капотом useContent() для отрисовки текущей страницы, а также всех вложенных макетов.

Этот компонент обычно располагается как дочерний компонент <body>, в большинстве стартовых шаблонов вы найдёте его в файле src/root.tsx (см. пример в QwikCityProvider).

<Form>

Компонент Form является обёрткой нативного элемента <form> и предназначен для работы с серверными действиями.

Поскольку этот компонент использует нативный элемент <form>, он будет работать в любом браузере с включенным JavaScript и без него. Кроме того, он расширяет нативный элемент <form>, перехватывая событие submit и предотвращая поведение по умолчанию, поэтому он будет вести себя как SPA (Single Page Application) вместо вызова полной перезагрузки страницы.

src/routes/login/index.tsx
import { component$ } from '@builder.io/qwik';
import { Form, action$ } from '@builder.io/qwik-city';
 
// это действие будет вызвано при отправке формы
export const useLoginAction = routeAction$((data, { cookies, redirect }) => {
  if (validate(data.username, data.password)) {
    cookies.set('auth', getAuthToken(data.username));
    throw redirect(302, '/dashboard');
  }
});
 
export default component$(() => {
  const login = useLoginAction();
 
  return (
    <Form action={login}>
      <input type="text" name="username" />
      <input type="password" name="password" />
      <button type="submit">Войти</button>
    </Form>
  );
});

Компонент Link работает как элемент якоря <a>, но вместо того, чтобы вызывать перезагрузку всей страницы, он осуществляет навигацию как SPA (Single Page Navigation). Это полезно, если вам нужно перемещаться без потери текущего состояния.

Помните, что полная перезагрузка страницы в Qwik чрезвычайно дёшева, другие фреймворки злоупотребляют ссылками SPA, потому что перезагрузка полной страницы требует от JS гидратации и выполнения заново. В случае с Qwik дело обстоит иначе. В ходе внутреннего тестирования мы обнаружили, что использование <a> обычно приводит к наиболее быстрому взаимодействию.

Под капотом компонент <Link> использует API useNavigate() и предотвращает поведение по умолчанию встроенного <a>:

import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
 
export const Link = component$<LinkProps>((props) => {
  const nav = useNavigate();
 
  return (
    <a
      preventdefault:click
      onClick$={() => {
        nav(props.href);
      }}
      {...props}
    >
      <Slot />
    </a>
  );
});

Использование

import { component$ } from '@builder.io/qwik';
import { Link } from '@builder.io/qwik-city';
 
export default component$(() => {
  return (
    <div>
      <a href="/docs" class="my-link">
        Полная перезагрузка страницы
      </a>
      <Link href="/docs" class="my-link">
        SPA-навигация
      </Link>
    </div>
  );
});

Участники

Спасибо всем участникам, которые помогли сделать эту документацию лучше!

  • manucorporat
  • adamdbradley
  • the-r3aper7
  • nnelgxorz
  • cunzaizhuyi
  • jakovljevic-mladen
  • barbosajlm
  • Eucer
  • eltociear
  • literalpie
  • Mhmdrza
  • ulic75
  • mhevery
  • jordanw66
  • igorbabko
  • mrhoodz
  • VinuB-Dev
  • billykwok
  • julianobrasil
  • hamatoyogi