データの取得
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 フックを使う
最後に fetch を呼び出したときのタイムスタンプを this.$fetchState.timestamp から取得することができます(SSR も含む)。このプロパティを 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 プロパティを見るパラメータを設定することができます。
Leoš Literák
Trizotti
Clément Ollivier
Sébastien Chopin
Marcello Bachechi
Rodolphe
Thomas Underwood
Shek Evgeniy
felipesuri
Lukasz Formela
Hugo Torzuoli
Sylvain Marroufin
Kareem Dabbeet
tramplay
Daniel Roe
verebelyicsaba
Adam
Nate Butler
Sandra Rodgers
Arpit Patidar
Matthew Kuehn
Steven DUBOIS
Travis Lindsey
syagawa
Maxime
かる
Al Power
Florent Delerue
quanghm
José Manuel Casani Guerra
Unai Mengual
kazuya kawaguchi
Michael Lynch
Tomachi
pooya parsa
Meir Roth
Brett
Adam Miedema
Thomas Bnt
Kazuki Furukawa
Anthony Ruelle
Christophe Carvalho Vilas-Boas
Roman Harmyder