Nuxt.js + TypeScript でページネーションが必要な一覧ページでのページング処理の実装方法について解説します。
Nuxt.jsでTypeScriptを利用する方法は以下のページを参考にしてください。
https://ja.nuxtjs.org/guide/typescript/
前提
今回の記事も参考ページにあるnuxt-property-decoratorの使用をしています。
インストール
//npmを利用している人は以下のコマンドで利用できます。
npm i -S nuxt-property-decorator
//yarnを利用している人は以下のコマンドを利用してください。
yarn add nuxt-property-decorator
decoratorでの書き方
<script lang="ts">
import {Component, Prop, Vue} from 'nuxt-property-decorator'
import BarComponent from '~/components/BarComponent.vue'
@Component({
components:{
BarComponent
}
})
export default class FooComponent extends Vue {
@Prop({type: String, required: true}) id!: string;
@Prop({type: Number, default: 0}) num?: number;
//dataオプション
flag = false
nameArray:string[] = ['hatanaka', 'kamiya', 'yamada', 'ito']
mounted(){
console.log('mounted !')
}
alertError(){
alert('エラーが発生しました。')
}
}
</script>
nuxt-property-decoratorの使用をしている場合、
依存コンポーネントを@Component
で読み込むことができます。
サンプルではBarComponent.vue
を依存コンポーネントとして読み込んでいます。
propsは@Prop
で定義でき、サンプルではid
とnum
というpropsを定義しています。
また、@Prop
のオプションはVueのpropで指定可能なオプションは全て網羅されています。
※ prop(Vue公式ドキュメント)
(2019年8月現在、Nuxt.js + TypeScriptは素の状態での型チェックが甘いため、オプションを指定することをお勧めします。)
stateはclassの直下にプロパティとして定義します。
(この文法はES2015のClassではなくTypeScriptのClassでのみ定義されています。)
サンプルではflag
というデフォルト値falseのものとnameArray
という文字列の配列をstateとして定義しています。
MethodやLifeCycle MethodはClassのメソッドとして定義します。
サンプルではLifeCycle Methodとしてmounted
を定義し、mounted時にconsole上にmounted !
と出力するように定義しています。
また、MethodとしてalertError
を定義し、こちらは実行された際にエラーが発生しました。
とアラートされるように定義しています。
nuxt-property-decoratorの基本的な使い方が確認できたら本題のページネーションの実装を見ていきましょう。
実際のコード例
<template>
<article class="foo-page">
<div>
{{pageText}}
</div>
<nuxt-link :to="prevPagePath">前のページへ</nuxt-link>
<nuxt-link :to="nextPagePath">次のページへ</nuxt-link>
</article>
</template>
<script lang="ts">
import { Component, Vue} from 'nuxt-property-decorator'
@Component({
components: {},
watchQuery: ['page']
})
export default class Foo extends Vue {
//data
pageNum = 0
pageText = '初期値'
//returnの内容でdataが上書きされる
asyncData({ query }) {
//クエリーがあればその数値を、なければ1を代入
const pageNum = !query.page ? 1 : query.page
//ページ番号を渡すと文字列を返してくる単純なAPI
const data = testApi
.fetch(pageNum)
.then(res => {
return {
pageText: res.pageText,
pageNum: 0
}
})
.catch(e => {
console.log(e)
})
data.pageNum = pageNum
return data
}
//クエリ付きのパスを返す
get prevPagePath(){
return '/foo?page=' + (pageNum - 1)
}
get nextPagePath(){
return '/foo?page=' + (pageNum + 1)
}
}
</script>
<template>
<div>
<nuxt :nuxt-child-key="$route.fullPath" />
</div>
</template>
<script>
</script>
<style lang="scss">
</style>
次のページへの遷移
サンプルでは、<nuxt-link >というコンポーネントを用いて他ページへのリンクを作成しています。
こちらは、to
で指定したpathへリンクするaタグ要素となるのでCSSなどで見た目のカスタマイズが行えます。
APIからのデータ取得
このページではasyncDataメソッドでapiからデータの取得を行っています。
asyncDataはSSRが行われるタイミングで実行されるようになっています。
しかし、Queryのみ更新された場合はasyncDataの再度呼び出しはされないため、
呼び出されるように設定を行う必要があります。
asyncDataが再度呼び出されるようにwatchQueryを設定する。
watchQueryで指定したqueryが更新された時に全てのコンポーネントメソッドを再実行するようになります。
(asyncData、fetch、validate、layoutなど)
また、default.vueで<nuxt :nuxt-child-key="$route.fullPath" />
を指定しないと再レンダリングされない場合があるようなので忘れずに指定します。
ちなみに
nuxt-property-decoratorを使用しない場合は、以下のようになります。
export default {
watchQuery: ['page'],
data () {
return {
pageNum : 0,
pageText : '初期値'
}
},
asyncData ({query}) {
const pageNum = !query.page ? 1 : query.page
const data = testApi
.fetch(pageNum)
.then(res => {
return {
pageText: res.pageText,
pageNum: 0
}
})
.catch(e => {
console.log(e)
})
data.pageNum = pageNum
return data
}
}
まとめ
- asyncDataやfetchメソッドを使用している時、そのままではQueryの更新で再度メソッドの呼び出しは行われない。
- Queryの監視を行いたい場合は、watchQueryを設定する。