OWNED MEDIAウェブ制作に役立つコンテンツを発信中!

Nuxt.jsでasyncDataやfetchを使って外部からのデータを非同期で取得してコンポーネントに出力する

シングルページアプリケーションなどのサイト制作では、ページ内のコンテンツを外部から取得して、動的にページを生成することもあるかと思います。そんな時には、ページが生成される前であったり、コンポーネントが更新される度にデータを取得しておく必要があります。Nuxt.jsでは、このようなケースにおいて「asyncData」と「fetch」と呼ばれるフックが用意されており、HTTPの非同期通信と合わせて使用されます。   今回はこの「asyncData」と「fetch」について具体的な使い方と違いについてまとめていきます。よく似ている両者ですが、少し異なる点もありますので注意が必要ですね。  
Axiosなどの非同期通信と合わせて使われるasyncDataとfetch
Nuxt.jsにおけるライフサイクルフックでは、asyncDataはコンポーネント初期化前に実行され、fetchはコンポーネント初期化直後に実行されます。順番でいうとこのような流れになります。
1. nuxtServerInit
2. middleware
3. validate
4. asyncData
5. beforeCreate
6. created
7. fetch
8. beforeMount
9. mounted
  Nuxt 2.12 以前では、asyncDataとfetch両方ともコンポーネントの初期化前に呼び出されているようになっていたようです。ですので、実行されるタイミングに少し違いがあるということですね。   それでは実際に使用例を見ていきます。ここではAxiosでHTTP非同期通信によってAPI経由で取得したデータを扱うという例で進めています。まずは、asyncDataを使ってページコンポーネント内に取得したデータを出力するケースです。 【pages/index.vue】
<template>
  <div>{{ posts }}</div>
</template>

<script>
  import { $axios } from 'axios';
  export default {
    .....
    async asyncData({ app }) {
      const response = await app.$axios.get('https://example.com/api/blog')
      return {
        posts: response.data
      }
    }
  }
</script>
  上記のように、Axiosでデータを取得し、オブジェクトの値に格納したデータとして返すようにしています。そしてテンプレート内に値を出力するようにしています。あるいはページコンポーネント内のdata変数に格納した上で扱うこともできます。こうすることで、テンプレート上で値を表示させたりすることができます。ポイントとなるのは「async / await」の処理で実行することで、APIからのデータ取得を待ってasyncDataの処理を実行するようにしています。   続いて、fetchを使うパターンです。ここでは取得したデータをコンポーネントからstoreへ格納し、gettersを使ってコンポーネント上に出力するケースです。 【components/sample.vue】
<template>
  <div>{{ posts }}</div>
</template>

<script>
  import { $axios } from 'axios';
  export default {
    .....
    async fetch() {
      const response = await this.$axios.get('https://example.com/api/blog')
      await this.$store.dispatch('fetchPosts', response.data)
    },
    computed: {
      posts() => this.$store.getters.getPosts
    }
  }
</script>
  先ほどのasyncDataとよく似ていますが、ここではコンポーネントから「dispatch」を使ってstoreファイルに定義したActionsを呼び出して、Mutations経由でstateの値に取得データを格納しています。あるいは「commit」メソッドで直接Mutationsを呼び出してstateの値を更新することもできます。そして、テンプレート側では算出プロパティを使ってgettersからstateの値を取得し、テンプレート内に出力しています。   このようにasyncDataとfetchではフックのタイミングが少し違うものの、大体同じように使われているのがわかります。ただ、少し違いもありそれに伴いしっかりと使い分けをするのも重要になってきます。  
asyncDataとfetchの違いと使い分け
先ほどのサンプルを見るとわかるようにasyncDataとfetchでは少し異なる点もあります。いくつかありますので使い分けと合わせて順に見ていきます。   1. asyncDataではthisが使えないので引数のContextオブジェクトを使う asyncDataはコンポーネント初期化前に実行されるのでthisにアクセスすることができず、thisを使った処理ができなくなります。その代わり、引数には、appやstore、routeなどのキーを持ったContextというオブジェクトが入ります。ここからstoreやrouteの情報にアクセスすることができます。下記のように引数であるContextのオブジェクトの中身を見てみるとこのようになっています。
asyncData( context ) {
  console.log(context)
}

// console
{
  $axios: ......,
  app: ......,
  base: ......,
  env: ......,
  nuxtState: ......,
  route: ......,
  store: ......,
  ......
}
  上記のサンプルでは分割代入で直接、appキーの値を参照するようにしています。これで、thisを使わずにstoreへのアクセスやルーティングの情報を扱うことができます。fetchではそのまま関数内でthisを使うことができます。   2. asyncDataはページコンポーネント内でのみ使用可能 もう一点、asyncDataの特徴としてpagesディレクトリ配下のページコンポーネントでしか使うことができないというのがあります。これは通常のコンポーネントにはasyncDataメソッドが用意されていないのが理由です。ですので、componentsディレクトリ配下にある通常のコンポーネントファイルではasyncDataではなくfetchを使うことになります。そのためページコンポーネントではasyncDataを、そのほかのコンポーネントではfetchを使うというのは使い分けの1つとして考えられるケースになりますね。   3. asyncDataは値をそのまま出力する、fetchはstoreファイル内に値を格納する asyncDataとfetchの用途として、asyncDataはページコンポーネントの値としてマージする、fetchはstoreにデータを格納するというようになっているようです。つまり、取得した値をstoreで管理するなどの場合にはfetchを使うという使い分けをすることができます。ちょうど上記の例が参考になるかと思います。   実際のサイト制作のケースであれば、ブログの個別記事ページの情報はasyncDataで取得し、ページテンプレート内に展開する、一覧ページのアーカイブリストなどは一覧ページ内で呼び出されるリストコンポーネント内でfetchを使って取得するというイメージでしょうか。  
  今回は、Nuxt.jsでasyncDataやfetchを使った非同期通信でのデータ取得とその違いや使い分けについてまとめてみました。ほとんど同じようなイメージがありますが、改めて知ると違いや使い分けが明確にわかりました。正しく理解して使い分けすることはやはり重要ですね。   (参考にさせて頂いたサイト) Nuxt.js データの取得
  • はてなブックマーク
  • Pocket
  • Linkedin
  • Feedly

この記事を書いた人

Twitter

SPONSORED

    KEYWORD SEARCH

    RECENT POSTS

    合同会社デザインサプライ -DesignSupply. LLC-

    サイト制作・開発 / 各種デザイン制作 / ウェブプロモーション企画

    合同会社デザインサプライ(DesignSupply. LLC)

    Office:大阪府大阪市天王寺区清水谷町3-22
    Email:info@designsupply-web.com
    • Twitter
    • Github
    CONTACT USSCROLL TO TOP
      • Facebook
      • Twitter
      • Github
      • Instagram