採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

Vue Router — 動的ルート

テクノロジ系 / L04 routing — ルーティング

Vue Router — 動的ルート

定義

{ path: "/users/:id", component: UserDetail }

:id でパラメータ。複数も OK:

{ path: "/users/:userId/posts/:postId", component: PostDetail }

useRoute で取得

<script setup lang="ts">
import { useRoute } from "vue-router";
import { computed } from "vue";

const route = useRoute();
const id = computed(() => parseInt(route.params.id as string, 10));
</script>

<template>
  <p>User {{ id }}</p>
</template>

route.params で URL パラメータ取得。

常に string なので数値化が必要。

クエリ

<script setup>
const route = useRoute();
const q = computed(() => (route.query.q as string) ?? "");
const page = computed(() => parseInt((route.query.page as string) ?? "1", 10));
</script>

/search?q=foo&page=2route.query.q = "foo"

params 変化時の再 fetch

<!-- 同じコンポーネントで :id が変わると ... -->
<!-- mount は走らない (コンポーネント再利用) -->

<script setup>
import { useRoute } from "vue-router";
import { ref, watchEffect } from "vue";

const route = useRoute();
const user = ref<User | null>(null);

watchEffect(async () => {
  const id = route.params.id;
  if (!id) return;
  user.value = await (await fetch(`/api/users/${id}`)).json();
});
</script>

watchEffectroute.params.id を見ているので、URL変化で自動再 fetch。

ルートを書き換える

<script setup>
const router = useRouter();

function gotoSearch() {
  router.push({ path: "/search", query: { q: "foo", page: 2 } });
}

function updateQuery() {
  router.push({ query: { ...router.currentRoute.value.query, page: 3 } });
}
</script>

object 形式で書ける。

クエリ更新で履歴に積まないなら router.replace(...)

ルート名で遷移

const routes = [
  { path: "/users/:id", component: UserDetail, name: "user-detail" },
];

router.push({ name: "user-detail", params: { id: 1 } });

name で参照すれば URL 構造変更に強い。

まとめ

  • :id で動的セグメント
  • useRoute().params.id で取得 (string)
  • params 変化は 同じコンポーネント再利用 なので watch で再 fetch
  • router.push({ name, params, query }) で型安全に近い遷移
  • router.replace は履歴に積まない

次は ネストルート

考えてみよう

既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。

Lv1: 基本 — useRoute

問題

// router
{ path: "/users/:id", component: UserDetail }
<!-- UserDetail.vue -->
<script setup lang="ts">
import { useRoute } from "vue-router";
import { computed } from "vue";

const route = useRoute();
const id = computed(() => parseInt(route.params.id as string, 10));
</script>

<template>
  <p>User ID: {{ id }}</p>
</template>

合格基準

/users/1 → "User ID: 1"

Lv2: 応用 — params 変化時の watchEffect

問題

<script setup lang="ts">
import { useRoute } from "vue-router";
import { ref, watchEffect } from "vue";

const route = useRoute();
const user = ref<any>(null);

watchEffect(async () => {
  const id = route.params.id;
  if (!id) return;
  user.value = null;
  const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  user.value = await res.json();
});
</script>

<template>
  <pre>{{ user }}</pre>
</template>

URL を /users/1 → /users/2 と変えると 同じ component 内で 再fetch。

合格基準

  • 同じ component 再利用
  • watchEffect で自動再取得

Lv3: 発展 — 検索クエリ

問題

<script setup>
import { useRoute, useRouter } from "vue-router";
import { computed } from "vue";

const route = useRoute();
const router = useRouter();

const q = computed(() => (route.query.q as string) ?? "");
const page = computed(() => parseInt((route.query.page as string) ?? "1", 10));

function updateQ(v: string) {
  router.push({ query: { ...route.query, q: v, page: "1" } });
}
</script>

<template>
  <input :value="q" @input="updateQ(($event.target as HTMLInputElement).value)" />
  <p>q={{ q }}, page={{ page }}</p>
</template>

URL バーに ?q=...&page=... が反映される。

合格基準

  • 検索文字が URL に同期
  • ブックマーク・共有可能

提出

submission.md に3問の回答を。