翻訳されたページ このページのコンテンツは古い可能性があります。

データの取得

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 フック

Nuxt 2.12 以前では、fetch フックは ページ コンポーネントに対してのみ使用でき、そしてコンポーネントへアクセスを持てないという違いがあります。もし fetch()context オブジェクトを受け取っているなら、それは「レガシー」な fetch フックだと考えられます。この機能は非推奨なので、asyncData または 無名ミドルウェア (anonymous middleware) に置き換えてください。

fetch は以下のように、サーバーサイドレンダリングではコンポーネントのインスタンスが作成されたとき、クライアントサイドでは遷移するときに呼び出されるフックです。fetch フックは解決される promise を(明示的に、または async/await を使って暗黙的に)返却するべきです:

  • サーバー上では、初期ページがレンダリングされる前
  • クライアント上では、コンポーネントがマウントされた後
静的ホスティング では、fetch フックはページが生成時のみに呼び出され、その結果はクライアントで使用するためにキャッシュされます。キャッシュの競合を避けるために、コンポーネントの名前を指定するか、代わりにユニークな fetchKey の実装を提供する必要があるかもしれません。

使い方

データの取得 (Fetching)

fetch フック内では、this を介してコンポーネントインスタンスにアクセスできます。

更新したいプロパティがすでに data() で宣言されていることを確認してください。宣言されている場合、取得したデータをこれらのプロパティに割り当てることができます。

fetch 動作の変更

fetchOnServer: Boolean または Function(デフォルト: true)。サーバーがページをレンダリングする際に fetch() を呼び出します。

fetchKey: String または Function(デフォルトはコンポーネントのスコープ ID またはコンポーネント名)、コンポーネントの fetch 結果を識別するキー(または一意のキーを生成する関数)。(Nuxt 2.15 以降で有効、詳細情報の GitHub プルリクエスト )。

fetchDelay: Integer(デフォルト: 200)。最小実行時間をミリ秒単位で設定します(過剰実行を防ぐため)。

fetchOnServer が falsy(false または false になる得る値を返す)の場合、fetch はクライアントサイドでのみ呼び出され、サーバーでコンポーネントをレンダリングする場合は、$fetchState.pendingtrue を返します。

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 をコンポーネントレベルで公開します:

  • pendingfetchクライアントサイドで呼び出されたときにプレースホルダーを表示するかを表す Boolean です
  • errornull もしくは fetch フックで発生した Error です
  • timestamp は最後に fetch したタイムスタンプ、keep-alive によるキャッシング で便利です

Nuxt が呼び出す fetch に加え、this.$fetch() を使うことでコンポーネント内から手動(例として非同期データの再読み込み)で fetch を呼び出すことができます。

components/NuxtMountains.vue
<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>
fetch フック内では this.$nuxt.context を使うことで、Nuxt context  にアクセスできます。

クエリ文字列の変化のリスニング

デフォルトでは、クエリ文字列の変化で fetch フックは呼び出されません。クエリ文字列の変化を監視するには、ウォッチャに $route.query を追加して $fetch を呼び出します:

export default {
  watch: {
    '$route.query': '$fetch'
  },
  async fetch() {
    // クエリ文字列の変化時にも呼び出される
  }
}

キャッシング

<nuxt/><nuxt-child/> コンポーネントで keep-alive ディレクティブを使うと、すでに訪れたページの fetch 呼び出しを保存することができます:

layouts/default.vue
<template>
  <nuxt keep-alive />
</template>

また、<nuxt> コンポーネントへ keep-alive-props プロパティを渡すことで、<keep-alive> に渡す props を指定することもできます。

layouts/default.vue
<nuxt keep-alive :keep-alive-props="{ max: 10 }" />

ページコンポーネントを 10 ページ分だけメモリに保存します。

エラーハンドリング

データをフェッチングするときエラーが発生した場合は、通常 Nuxt エラーページはロードされません。そして、 fetch() 内で Nuxt redirect または error メソッドを使うべきではありません。代わりに、$fetchState.error を使ったコンポーネント内でエラー処理する必要があります。

データのフェッチングでエラーが発生した場合、$fetchState.error でチェックし、エラーメッセージを表示します。

components/MountainsList.vue
<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 秒のキャッシュを追加することができます:

pages/posts/_id.vue
<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

asyncDatapages でのみ使用可能で、このフック内では this にアクセスすることはできません。

asyncData はユニバーサルなデータ取得のためのもう 1 つのフックです。非同期な状態を保存するために、コンポーネントのインスタンスにプロパティをセットする(または Vuex アクションをディスパッチする)必要がある fetch とは異なり、asyncData は単にその返却された値をコンポーネントのデータにマージします。以下は、@nuxt/http ライブラリを使った例です:

pages/posts/_id.vue
<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 つの基本的なオプションがあります:

  1. Nuxt 2.12 以降のバージョンで有効になった 新しい fetch フック を使う
  2. mounted フックで API を呼び出し、ロード時にデータプロパティを設定します。欠点: サーバーサイドレンダリングでは機能しません。
  3. ページコンポーネントの asyncData メソッドで API を呼び出し、データをプロパティとしてサブコンポーネントに渡します。サーバーのレンダリングは正常に機能します。欠点: ページの asyncData は他のコンポーネントのデータを読み込むため読みにくい可能性があります。

クエリ文字列の変化のリスニング

デフォルトでは、クエリ文字列の変化で asyncData メソッドは呼び出されません。ページネーションコンポーネントを作成するときなどにこの挙動を変えたい場合は、ページコンポーネントの watchQuery プロパティを見るパラメータを設定することができます。

このページをGitHubで編集する 更新日 Mon, Oct 25, 2021