API リファレンス

useContent()

useContent() 関数は、現在のルートに最も近いコンテンツ情報を取得します。返されるオブジェクトには以下が含まれます。

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

headings 配列には、Markdownファイルの <h1> から <h6> までの HTML 見出し要素に関するデータが含まれています。

メニューは、menu.md ファイルで宣言されたコンテキストデータです。ファイル形式と場所の詳細については、メニューファイル定義 を参照してください。

useDocumentHead()

ドキュメントの headメタデータを読み取るには、useDocumentHead() 関数を使用します。

useDocumentHead() は、以下を含む読み取り専用の DocumentHead オブジェクトを取得します。

export interface DocumentHead {
  /**
   * Represents the `<title>` element of the document.
   */
  readonly title?: string;
  /**
   * Used to manually set meta tags in the head. Additionally, the `data`
   * property could be used to set arbitrary data which the `<head>` component
   * could later use to generate `<meta>` tags.
   */
  readonly meta?: readonly DocumentMeta[];
  /**
   * Used to manually append `<link>` elements to the `<head>`.
   */
  readonly links?: readonly DocumentLink[];
  /**
   * Used to manually append `<style>` elements to the `<head>`.
   */
  readonly styles?: readonly DocumentStyle[];
  /**
   * Arbitrary object containing custom data. When the document head is created from
   * markdown files, the frontmatter attributes that are not recognized as a well-known
   * meta names (such as title, description, author, etc...), are stored in this property.
   */
  readonly frontmatter?: Readonly<Record<string, any>>;
}

すべてのスターターには、ドキュメントの <head> 要素の生成を担当する <RouterHead> コンポーネントが含まれています。これは、useDocumentHead() 関数を使用して現在のheadメタデータを取得し、適切な <meta><link><style>、および <title> 要素をレンダリングします。

src/components/router-head/router-head.tsx
import { component$ } from '@builder.io/qwik';
import { useDocumentHead } from '@builder.io/qwik-city';
 
/**
 * The RouterHead component is placed inside of the document `<head>` element.
 */
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()

現在の場所の RouteLocation オブジェクトを取得するには、useLocation() 関数を使用します。

useLocation() 関数は、現在のURLとパラメータを提供します。また、アプリが現在ナビゲート中かどうかを判断します。これは、ローディングインジケーターを表示するのに役立ちます。

export interface RouteLocation {
  /**
   * Route params extracted from the URL.
   */
  readonly params: Record<string, string>;
  /**
   * The current URL.
   */
  readonly url: URL;
  /**
   * True if the app is currently navigating.
   */
  readonly isNavigating: boolean;
}

useLocation() の戻り値は document.location と似ていますが、グローバルな location オブジェクトが存在しないサーバーで使用しても安全であり、リアクティブであるため追跡できます。

パスルートパラメータ

useLocation() は、ルートパラメータ をパラメータとしてエンコードします。

次のような場合を想定します。

  • ファイル: src/routes/sku/[skuId]/index.tsx
  • ユーザーが https://example.com/sku/1234 に移動します。
  • その場合、skuIduseLocation().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>SKU</h1>
      {loc.isNavigating && <p>Loading...</p>}
      <p>pathname: {loc.url.pathname}</p>
      <p>skuId: {loc.params.skuId}</p>
    </>
  );
});

上記のコードは以下を生成します。

<h1>SKU</h1>
<p>pathname: /sku/1234/</p>
<p>skuId: 1234</p>

root.tsx での useLocation はサポートされていません

root.tsx から現在のURLにアクセスするには、次のパターンを使用します。

const serverDataUrl = useServerData<string>('url');
const url = new URL(serverDataUrl || 'https://unknown');

useLocation は読み取り専用のAPIであることに注意してください。返された loc オブジェクトの値を変更しようとしないでください。代わりに、useNavigate() APIを調べてください。

useNavigate()

useNavigate() フックは、ユーザーのクリックを必要とせず、ページ 전체를 다시 로드 하지 않고도 プログラムで次のページに移動する関数を返します。 この関数は、文字列引数を指定して呼び出すことで新しいパスを「プッシュ」したり、引数なしで呼び出すことでページのSPAリフレッシュを実行したりできます。 これは、<Link> コンポーネントがSPAナビゲーションをサポートするために内部的に使用するAPIです。

import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
 
export default component$(() => {
  const nav = useNavigate();
 
  return (
    <>
      <button
        onClick$={async () => {
          // SPA navigate to /dashboard
          await nav('/dashboard');
        }}
      >
        Go to dashboard
      </button>
 
      <button
        onClick$={async() => {
          // refresh page: call without arguments
          await nav();
        }}
      >
        Refresh page
      </button>
    </>
  );
});

このコンポーネントには、クリックするとページをリロードせずに /dashboard に移動するボタンがあります。

SEOとアクセシビリティのために、ユーザーインタラクション後にプログラムで新しいページに移動するには、useNavigate() の代わりに <Link> コンポーネントを使用することをお勧めします。

戻る

前のページにプログラムで戻るには、useNavigateフックとuseLocationフックを使用します。

import { component$ } from '@builder.io/qwik';
import { useNavigate, useLocation } from '@builder.io/qwik-city';
 
export const BackButton = component$(() => {
  const nav = useNavigate();
  const loc = useLocation();
 
  return (
    <button onClick$={() => loc.prevUrl ? window.history.back() : nav('/')}>
      Go Back
    </button>
  );
});
 

nav関数のフォールバックにより、前のURL(loc.prevUrl)が使用できない場合、ユーザーはデフォルトのパス(例:ルートパス/)にリダイレクトされます。これは、アプリ内で別のページから移動せずにユーザーが特定のページに直接アクセスする場合など、ナビゲーション履歴に前のURLが含まれていないシナリオで役立ちます。

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$() 関数は、指定されたページ/ミドルウェア/レイアウトで新しいサーバーアクションを宣言するために使用されます。Qwik City は、ボタンのクリックやフォームの送信など、ユーザーの操作後に呼び出されたアクションのみを実行します。

詳細は、サーバーアクションのセクションを参照してください。

<QwikCityProvider>

QwikCityProvider コンポーネントは、既存のドキュメントで Qwik City を初期化し、useContent()useLocation() など、Qwik City が機能するために必要なコンテキストを提供します。

このコンポーネントは通常、アプリケーションのルートに配置されます。ほとんどのスターターでは、src/root.tsx ファイルにあります。

src/root.tsx
export default component$(() => {
  /**
   * The root of a QwikCity site always start with the <QwikCityProvider> component,
   * immediately followed by the document's <head> and <body>.
   *
   * Don't remove the `<head>` and `<body>` elements.
   */
 
  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 コンテキストを初期化します。useContent() など、Qwik City コードがテストで機能するために必要なコンテキストを提供します。反対に、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';
 
// Component with two props. Uses <Link> internally. Omitted for brevity
import { Card } from './card';
 
const cases = [
  {text: 'qwik', link:'https://qwik.dokyumento.jp/docs/api'}, 
  {text: 'vitest', link: 'https://vitest.dokyumento.jp'}
];
 
test.each(cases)('should render card with %s %s', async ({text, link}) => {
  const { screen, render } = await createDOM();
  await render(
    <QwikCityMockProvider>
      <Card text={text} link={link} />
    </QwikCityMockProvider>,
  );
  expect(screen.innerHTML).toMatchSnapshot();
});

テスト中の navigate 動作をカスタマイズするために、goto プロパティを渡すことができます。

src/components/button.spec.tsx
import { $ } from '@builder.io/qwik';
import { createDOM } from '@builder.io/qwik/testing';
import { test, expect, vi } from 'vitest';
 
// Component with one prop. Uses useNavigate internally. Omitted for brevity
import { Button } from '../button';
 
const goto = vi.fn(async (path, options) => {
  console.log(`Navigating to ${path} with ${options}`);
});
 
test('should render the button and navigate', async () => {
  const { screen, render, userEvent } = await createDOM();
  const goto$ = $(goto);
  await render(
    <QwikCityMockProvider goto={goto$}>
      <Button id="button" />
    </QwikCityMockProvider>,
  );
  expect(screen.innerHTML).toMatchSnapshot();
  await userEvent('#button', 'click');
  expect(goto).toHaveBeenCalled();
});

<RouterOutlet>

RouterOutlet コンポーネントは、特定の瞬間に一致するルートをレンダリングする役割を担います。内部的には useContent() を使用して現在のページとすべてのネストされたレイアウトをレンダリングします。

このコンポーネントは通常、<body> の子として配置されます。ほとんどのスターターでは、src/root.tsx ファイルにあります(QwikCityProvider の例を参照)。

<Form>

Form コンポーネントは、ネイティブの <form> 要素のラッパーであり、サーバーアクションと連携するように設計されています。

このコンポーネントはネイティブの <form> 要素を使用するため、JavaScript が有効になっているかどうかにかかわらず、あらゆるブラウザで動作します。さらに、submit イベントをキャプチャしてデフォルトの動作を防ぐことで、ネイティブの <form> 要素を拡張します。そのため、ページ全体をリロードするのではなく、SPA(シングルページアプリケーション)のように動作します。

src/routes/login/index.tsx
import { component$ } from '@builder.io/qwik';
import { Form, routeAction$ } from '@builder.io/qwik-city';
 
// this action will be called when the form is submitted
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">Login</button>
    </Form>
  );
});

Link コンポーネントは、<a> アンカー要素のように機能しますが、ページ全体をリロードする代わりに、SPA(シングルページナビゲーション)としてナビゲートします。これは、現在の状態を失うことなくナビゲートする必要がある場合に役立ちます。

Qwik では、ページ全体の再読み込みは非常に軽量であることに注意してください。他のフレームワークは SPA リンクを多用しますが、これはページ全体の再読み込みには JS によるハイドレーションとすべての実行のやり直しが必要になるためです。Qwik の場合はそうではありません。内部テストの調査により、<a> を使用すると、通常は最も軽快なインタラクションが実現することがわかっています。

内部的には、<Link> コンポーネントは useNavigate() API を使用し、ネイティブの <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">
        full-page reload
      </a>
      <Link href="/docs" class="my-link">
        spa navigation
      </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
  • srapport