Vue.jsでページネーションを実装していましたが、Vue Routerのインスタンスになぜかアクセスできず困ったため、備忘録として残します。
問題
Vuetifyを使って以下のようにページネーションの実装を試みていました。
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import useSamplePage from './composables/useSamplePage'
import { useRoute, useRouter } from 'vue-router';
const { samplePage, setupSamplePage } = useSamplePage()
const route = useRoute()
watch(() => route.query.page, async () => {
setupSamplePage()
}, {
immediate: true
})
const currentPage = ref(1)
const router = useRouter()
const onChange = () => {
if (!currentPage.value) return
router.push({
path: `/sample`,
query: { page: currentPage.value },
})
}
</script>
<template>
<v-container>
<p>{{ `sampleStateの値: ${sampleState}` }}</p>
<v-pagination v-model="currentPage" :length="5" @click="onChange" />
</v-container>
</template>
import { ref } from "vue";
import { useRoute } from "vue-router";
const useSamplePage = () => {
const samplePage = ref(0);
const setupSamplePage = () => {
const route = useRoute();
const page = route.query.page || 1;
if (page) {
samplePage.value = Number(page);
}
};
return {
samplePage,
setupSamplePage,
};
}
export default useSamplePage;
ページネーションをクリックするとroute.query.page
に選択されたページ番号が格納され、ルーティングが変わります。
そしてroute.query.page
の値をwatch
で監視し、変更があるたびにComposablesとして切り出したsetupSamplePage
関数が実行される仕様です。
これをブラウザで表示すると、以下のようになります↓
あとはページを選択するたびに「pageの値: 」も連動して切り替わってくれれば良いのですが、うまくいかず、、。
番号をクリックするとURLはhttp://localhost:5173/sample?page=2
となっていますが、画面の番号は1
のままです。
コンソールを確認するとエラーが出ていました、、。
どうやらuseSamplePage.ts
ファイルのconst page = route.query.page || 1;
の箇所でrouteオブジェクトがundefined
になっているようです。
しかし、setupSamplePage
関数の中でconst route = useRoute();
と記述しているのに、なぜrouteがundefined
になってしまうかが分からず、時間をかけてしまいました、、。
解決方法
結論として、useSamplePage.ts
の中にconst route = useRoute();
を記述せず、SampleView.vue
の中でrouteオブジェクトを取得し、setupSamplePage
関数に引数として渡すことでエラーが解消できました。
修正後のファイルは以下のとおりです。
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import useSamplePage from './composables/useSamplePage'
import { useRoute, useRouter } from 'vue-router';
const { samplePage, setupSamplePage } = useSamplePage()
const route = useRoute()
watch(() => route.query.page, async () => {
// 引数として route.query.page を渡す
setupSamplePage(Number(route.query.page))
}, {
immediate: true
})
watch(() => route.query.page, async () => {
// 引数として route.query.page を渡す
const page = Number(route.query.page) || 1;
setupSamplePage(page)
}, {
immediate: true
})
const currentPage = ref(1)
const router = useRouter()
const onChange = () => {
if (!currentPage.value) return
router.push({
path: `/sample`,
query: { page: currentPage.value },
})
}
</script>
<template>
<v-container>
<p>{{ `samplePageの値: ${samplePage}` }}</p>
<v-pagination v-model="currentPage" :length="5" @click="onChange" />
</v-container>
</template>
import { ref } from "vue";
import { useRoute } from "vue-router";
const useSamplePage = () => {
const samplePage = ref(0);
// route.query.page の値を関数内で取得せず、引数として受け取る
const setupSamplePage = (page: number) => {
samplePage.value = Number(page);
};
return {
samplePage,
setupSamplePage,
};
}
export default useSamplePage;
setup
関数の実行が完了する前の時点ではVue Routerがまだ準備中の状態なので、useRoute
を実行してもrouteオブジェクトが取得されず、冒頭のエラーが発生していたようです。
これでもう一度ブラウザを確認すると、、
選択したページネーションに応じて、画面の表示も切り替わるようになりました!
おわりに
まだ根本から理解できていない気がしていますが、とりあえず解決方法だけまとめました。
コメント