SvelteKitで今いるURLを取得する

ルーン登場(Svelteのリアクティブな状態管理)をきっかけにSvelte破壊的変更やりすぎな、、ということで、同じタイトルのQiita記事が今では非推奨になった内容だったので現在の書き方を載せておきます。この記事も1年後には古い書き方と言われてたりして、、(笑えない)

公式ドキュメント

$app/state • SvelteKit Docs
$app/state • SvelteKit documentation

以前は$app/store を利用してpage 情報を取得していましたが、SvelteKit 2.12でルーンベースで状態管理する $app/stateが導入され、$app/storesは非推奨になりました。

SvelteKitではバージョンによってストアの利用可否が異なり、SvelteKit 3では削除されています。

現在の書き方:$app/state

現行の基本形は、$app/state から page をインポートして、そのプロパティを読む方法です。ストアの場合と違って、先頭の”$”は付けませんので注意。

<script>
  import { page } from '$app/state';
</script>

<p>現在のURL:{page.url.href}</p>
<p>パス:{page.url.pathname}</p>
<p>ルートID:{page.route.id}</p>

page からは、現在のURL、ルートのパラメーター、ルートID、ページデータ、フォームの状態、HTTPステータスやエラー情報などを参照できます。

たとえば /products/[slug] のようなルートでは、page.params.slug から現在のパラメーターを確認できます。

値をスクリプト内で使うときは$derivedにする

pageはナビゲーションに応じて変化するリアクティブな状態です。

テンプレート内で直接参照する場合は更新が反映されますが、スクリプト内で値を変数に取り出す場合は、ルーンを使って依存関係を表す必要があります。

<script>
  import { page } from '$app/state';

  const pathname = $derived(page.url.pathname);
  const slug = $derived(page.params.slug);
</script>

<p>現在のパス:{pathname}</p>
<p>商品スラッグ:{slug}</p>

次のように通常の変数へ一度だけ代入した場合、初期表示の値を保持したままになり、クライアント側のページ遷移後に更新されません。

<script>
  import { page } from '$app/state';

  // 初期値を読むだけ。ページ遷移後に追従しない
  const pathname = page.url.pathname;
</script>

公式ドキュメントでは、レガシー構文の $: も $app/state の変更を追跡しないと説明されています。

$app/state を使うコンポーネントでは、リアクティブな派生値に $derived を使いましょう。

loadで取得するデータとpage.dataの使い分け

page.data には現在のページやレイアウトの load 関数が返したデータが統合されており、レイアウトなどコンポーネントツリーの別の場所から参照したい場合に便利です。

ただし、ページ固有のデータ取得そのものは、引き続き +page.js や +page.server.js の load 関数で行うのが基本です。URLのパラメーターからデータを読み込む処理を、コンポーネント内で page を見て直接置き換えるという意味ではありません。

<!-- +page.svelte -->
<script>
  let { data } = $props();
</script>

<h1>{data.product.name}</h1>

また、サーバー側では $app/state の値はコンポーネントのレンダリング中に参照します。

load 関数の中で現在のリクエスト情報を読むための仕組みとして使うものではありません。load では関数引数から url や params を受け取ります。

ルーンモードへ移行するときの注意

  • storeの購読記法と混ぜない:$app/state の page はストアではないため、$page のような自動購読記法は使いません。
  • 派生値はルーンで宣言する:スクリプト内で現在のURLやパラメーターを変数に保持する場合は、$derived(...) を使います。
  • 既存の$:を見直す:ルーンモードのコンポーネントでは、従来のリアクティブ宣言 $: は使えません。値の派生には $derived、副作用には必要に応じて $effect を使います。
  • 移行はコンポーネント単位で考える:Svelte 5では既存のレガシーモードとルーンモードを段階的に扱えます。移行対象のコンポーネントでは、propsや状態宣言など周辺の構文もあわせて確認します。
  • URLは読み取り専用として扱う:現行ドキュメントでは page.url は読み取り専用です。クエリを書き換えるときはURLをコピーして操作し、ナビゲーションにはSvelteKitの goto など適切なAPIを使います。

タイトルとURLをコピーしました