Nuxt.js

【Nuxt.jsに入門してみた】asyncData()とfetch()について

2020/02/09

「APIから持ってきたデータを表示する」そんなページをSPAで構築する際には、Vue.jsの場合、「created()」フックなどにAPIを叩く処理を書くパターンが多いのではないかと思います。

Nuxt.jsで開発する場合にも、「created()」フックを使って同様のことが行えます。

しかし「created()」は、あくまでブラウザ側での実行になります。Nuxt.jsを使ってSSRを行いたい場合には、サーバー側でデータ取得の完了まで行いたいケースが多いはずです。

この記事では、そんな時に使える「asyncData()」と「fetch()」について紹介します。

asyncData()について

asyncDataの使い方

コンポーネント(.vueファイル)内で、以下のように呼び出すことが可能です。 (※「asyncData()」を使うことができるのは、「pages」ディレクトリ配下のコンポーネントだけです)
import axios from 'axios'

export default {
  asyncData() {  // promiseを返すようにする
    return axios.get('https://URL')
      .then(result => {
      	return {
      	  itemData: {
      	    ...result.data
          }
      	}
      })
  }
}

// もちろん、以下のように「async/await」で書けます。
// async asyncData() {
//   const result = await axios.get('https://URL')
//   return {
//     itemData: {
//       ...result.data
//     }
//   }
// }

まず、promiseを返すように書く必要があります。 (promiseの解決をサーバー側で待ってから、クライアント側に処理が渡ります)

そして、data()オプションと同じように、オブジェクトを返すようにします。 返したオブジェクトは、data変数にマージされます。

※asyncData()とdata()で、同じキー名の変数を入れないように注意です。 (data()で上書きされてしまうため)

「context」について

「asyncData()」は、サーバー側での実行(コンポーネントのインスタンス化前)になるので、処理内で「this」を使うことができません。 代わりに、引数として「contextオブジェクト」が渡されます。

API: コンテキスト - NuxtJS

contextオブジェクトには、リクエスト情報やパラメータなどのデータが入っています。 必要なデータには、contextオブジェクトを介してアクセスする形になります。

import axios from 'axios'

async asyncData(context) {
  // URLのパラメータを取得したり。
  const id = context.params.id

  const result = await axios.get('https://URL' + id)
  return {
    itemData: {
      ...result.data
    }
  }
}

asyncData()の実行タイミングについて

asyncData()がサーバー側で実行されるのは、アプリケーションへの初回アクセス時のみです。 (URLへの直接アクセス・リロードなどの形でページに遷移した場合など)

最初の一回はサーバー側で実行されますが、それ以降はSPAとして動作することになります。(ブラウザ側で実行される)

asyncData()は、

・サーバー側 ・クライアント側

上記のどちらでも実行されるので、その点をコード書く時には意識しておく必要があります。

例えば「localStorage」は、クライアント側でしかアクセスできません。(サーバー側ではエラーになります。) なので「process.client」などを利用して条件分岐するなど、工夫が必要です。

  if (process.client) {
    // ブラウザ側でのみ行いたい処理
  }

fetch()について

fetch()はサーバー側でデータを取得して、その値をstoreに格納したい場合に使うメソッドです。

使い方自体は、ほとんど「asyncData()」と一緒です。

import axios from 'axios'

export default {
  async fetch(context) {
    const result = await axios.get('https://URL')
    context.store.commit('testMutations', result.data)
  }
}

asyncData()と同様に、promiseを返すようにします。そして、上記の例のようにデータをstoreに格納すればOKです。(contextオブジェクトを介して、storeにアクセスすることが可能です。)

asyncData()と同様に、最初の一回はサーバ側で実行されて、 その後は、fetch()を利用しているコンポーネントにアクセスする度に、毎回ブラウザ側で実行されます。

asyncData()もfetch()も、似た挙動をするメソッドですが、

  • asyncData():取得してきたデータをdata変数として扱いたい時
  • fetch():取得してきたデータをstoreに格納したい時

上記のように、目的に応じて使います。