データの取得
Nuxt では、API からデータを取得する方法が 2 つあります。fetch メソッドまたは asyncData メソッドを使用できます。
Nuxt はコンポーネントの mounted() フックでデータを取得するなど、クライアントサイドアプリケーションにおける従来の Vue のデータの取得パターンをサポートしています。しかしユニバーサルアプリケーションでは、サーバーサイドレンダリング中にデータをレンダリングするために Nuxt 特有のフックを使う必要があります。これにより、必要なデータがすべて存在する状態でページをレンダリングすることができます。
Nuxt には、データを非同期に読み込むためのフックが 2 つあります。
-
asyncData。このフックは、 ページ コンポーネントでのみ使用できます。fetchとは異なり、クライアントサイドレンダリング中にローディングプレースホルダーを示しません。そのかわり、フックが解決するまでルートナビゲーションをブロックし、失敗した場合はエラーページを表示します。 -
fetch(Nuxt 2.12 以降)。どのコンポーネントにでも配置することができ、(クライアントサイドレンダリング中の)ローディング状態やエラーをレンダリングするショートカットを提供します。
これらのフックは、あなたが選ぶ どのようなデータ取得ライブラリ とでも一緒に使うことができます。HTTP API へリクエストを送るために @nuxt/http または @nuxt/axios を使用することをおすすめします。認証ヘッダーの設定のような、これらのライブラリのより詳しい情報はそれぞれのドキュメントで見つけることができるでしょう。
fetch または asyncData を定義し、それをコンポーネントやページでも定義すると、ミックスイン関数は上書きされ呼び出されません。fetch フック
fetch フックがありました。もし fetch() が context 引数を受け取るように書かれているなら、それはレガシーな fetch フックとして扱われます。この機能は非推奨なので、asyncData または 無名ミドルウェア (anonymous middleware) に置き換えてください。fetch はサーバーサイドレンダリングではコンポーネントのインスタンスが作成された後に呼び出され、クライアントサイドでは遷移時に呼び出されるフックです。fetch フックは下記のタイミングで解決される promise を(明示的に、または async/await を使って暗黙的に)返却するべきです:
- サーバー上では、初期ページのレンダリングより前
- クライアント上では、コンポーネントのマウントより後
使い方
データの取得 (Fetching)
fetch フック内では、this を介してコンポーネントインスタンスにアクセスできます。
data() で宣言されていることを確認してください。宣言されている場合、取得したデータをこれらのプロパティに割り当てることができます。fetch 動作の変更
fetchOnServer: Boolean または Function(デフォルト: true)。サーバーがページをレンダリングする際に fetch() を呼び出します。
fetchKey: String または Function(デフォルトはコンポーネントのスコープ ID またはコンポーネント名)、コンポーネントの fetch 結果を識別するキー(または一意のキーを生成する関数)。(Nuxt 2.15 以降で有効、詳細情報の GitHub プルリクエスト )。サーバーでレンダリングされたページをハイドレートする際、このキーはサーバーサイド fetch() の結果をクライアントサイドのコンポーネントデータにマッピングするために使用されます。 詳細は PR を参照してください。
fetchDelay: Integer(デフォルト: 200)。最小実行時間をミリ秒単位で設定します(高速な画面ちらつきを防ぐため)。
fetchOnServer が falsy(false または false と評価される値)の場合、fetch はクライアントサイドでのみ呼び出され、サーバーでコンポーネントをレンダリングしている間は $fetchState.pending は true を返します。
export default {
data: () => ({
posts: []
}),
async fetch() {
this.posts = await this.$http.$get('https://api.nuxtjs.dev/posts')
},
fetchOnServer: false,
// 複数のコンポーネントは同じ `fetchKey` を返すことができ、Nuxt はそれら両方を別々に追跡します
fetchKey: 'site-sidebar',
// 他の手段として、もっとコントロールしたい場合は、コンポーネントのインスタンスにアクセスできる関数を渡すこともできます
// これは `created` で呼び出され、フェッチされたデータに依存してはいけません
fetchKey(getCounter) {
// getCounterは、ユニークな fetchKey を生成する際に、シーケンス内の次の番号を
// 取得するために呼び出すことができるメソッドです
return this.someOtherData + getCounter('sidebar')
}
}
fetch 状態へのアクセス
fetch フックは、以下のプロパティを持つ this.$fetchState をコンポーネントレベルで公開します:
-
pendingはfetchがクライアントサイドで呼び出されたときにプレースホルダーを表示するかを表すBooleanです -
errorはnullもしくはfetchフックで発生したErrorです -
timestampは最後に fetch した時刻で、keep-aliveによるキャッシング のために使えます
Nuxt が呼び出す fetch に加え、this.$fetch() を使うことでコンポーネント内から手動(例として非同期データの再読み込み)で fetch を呼び出すことができます。
<template>
<p v-if="$fetchState.pending">Fetching mountains...</p>
<p v-else-if="$fetchState.error">An error occurred :(</p>
<div v-else>
<h1>Nuxt Mountains</h1>
<ul>
<li v-for="mountain of mountains">{{ mountain.title }}</li>
</ul>
<button @click="$fetch">Refresh</button>
</div>
</template>
<script>
export default {
data() {
return {
mountains: []
}
},
async fetch() {
this.mountains = await fetch(
'https://api.nuxtjs.dev/mountains'
).then(res => res.json())
}
}
</script>
this.$nuxt.context を使うことで、Nuxt context にアクセスできます。クエリ文字列の変化のリスニング
デフォルトでは、クエリ文字列の変化で fetch フックは呼び出されません。クエリ文字列の変化を監視するには、ウォッチャに $route.query を追加して $fetch を呼び出します:
export default {
watch: {
'$route.query': '$fetch'
},
async fetch() {
// クエリ文字列の変化時にも呼び出される
}
}
キャッシング
<nuxt/> や <nuxt-child/> コンポーネントで keep-alive ディレクティブを使うと、すでに訪れたページの fetch 呼び出しを保存することができます:
<template>
<nuxt keep-alive />
</template>
また、<nuxt> コンポーネントへ keep-alive-props プロパティを渡すことで、<keep-alive> に渡す props を指定することもできます。
<nuxt keep-alive :keep-alive-props="{ max: 10 }" />
ページコンポーネントを 10 ページ分だけメモリに保存します。
エラーハンドリング
fetch() 内で Nuxt redirect または error メソッドを使うべきではありません。代わりに、$fetchState.error を使ったコンポーネント内でエラー処理する必要があります。データのフェッチングでエラーが発生した場合、$fetchState.error でチェックし、エラーメッセージを表示します。
<template>
<div>
<p v-if="$fetchState.pending">Loading....</p>
<p v-else-if="$fetchState.error">Error while fetching mountains</p>
<ul v-else>
<li v-for="(mountain, index) in mountains" :key="index">
{{ mountain.title }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
mountains: []
}
},
async fetch() {
this.mountains = await fetch(
'https://api.nuxtjs.dev/mountains'
).then(res => res.json())
}
}
</script>
activated フックを使う
Nuxt は最後に fetch を呼び出した時刻(SSR も含む)を this.$fetchState.timestamp に直接格納します。このプロパティを activated フックと組み合わせることで、fetch に 30 秒のキャッシュを追加することができます:
<template> ... </template>
<script>
export default {
data() {
return {
posts: []
}
},
activated() {
// 最後の fetch から30秒以上経っていれば、fetch を呼び出します
if (this.$fetchState.timestamp <= Date.now() - 30000) {
this.$fetch()
}
},
async fetch() {
this.posts = await fetch('https://api.nuxtjs.dev/posts').then(res =>
res.json()
)
}
}
</script>
最後の fetch の呼び出しが 30 秒以内であれば、同じページへの遷移で fetch は呼ばれません。
Async Data
asyncData はユニバーサルなデータ取得のためのもう 1 つのフックです。非同期な状態を保存するために、コンポーネントのインスタンスにプロパティをセットする(または Vuex アクションをディスパッチする)必要がある fetch とは異なり、asyncData は単にその返却された値をコンポーネントのデータにマージします。以下は、@nuxt/http ライブラリを使った例です:
<template>
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.description }}</p>
</div>
</template>
<script>
export default {
async asyncData({ params, $http }) {
const post = await $http.$get(`https://api.nuxtjs.dev/posts/${params.id}`)
return { post }
}
}
</script>
fetch と異なり、asyncData フックから返却される promise は ルートの遷移の間 に解決されます。つまり、"loading placeholder" はクライアントサイドの遷移で表示されないということです(ただし読み込み中の状態をユーザーに示すために ローディングバー を使うことができます。Nuxt は代わりに asyncData フックの終了を待ってから、次のページへ移動したりエラーページ を表示したりします)。
このフックはページレベルのコンポーネントのためだけに使うことができます。fetch と異なり、asyncData はコンポーネントインスタンス (this) にアクセスすることはできません。
そのかわりに、context を引数として受け取ります。asyncData をデータの取得のために使うことができ、Nuxt は返却されたオブジェクトとコンポーネントのデータとの浅いマージ(shallow merge)を自動的に行います。
今後追加される例では、API からのデータの取得におすすめの @nuxt/http を使用します。
コンポーネントの非同期データ?
コンポーネントには asyncData メソッドがないため、コンポーネント内でサーバーから非同期データを直接取得することはできません。この制限を回避するには、3 つの基本的なオプションがあります:
-
Nuxt 2.12 以降のバージョンで有効になった 新しい
fetchフック を使う -
mountedフックで API を呼び出し、ロード時にデータプロパティを設定します。欠点: サーバーサイドレンダリングでは機能しません。 -
ページコンポーネントの
asyncDataメソッドで API を呼び出し、データをプロパティとしてサブコンポーネントに渡します。サーバーのレンダリングは正常に機能します。欠点: ページのasyncDataは他のコンポーネントのデータを読み込むため読みにくい可能性があります。
クエリ文字列の変化のリスニング
デフォルトでは、クエリ文字列の変化で asyncData メソッドは呼び出されません。ページネーションコンポーネントを作成するときなどにこの挙動を変えたい場合は、監視するパラメータをページコンポーネントの watchQuery プロパティに設定することができます。