【Nuxt】NuxtでAxios
はじめに
こんにちは!大ちゃんの駆け出し技術ブログです。
今回はNuxt.jsでAxiosを使用した簡単なチュートリアルを記述します。
API取得サイト
AxiosはJSONレスポンスを受け取るのでJSONレスポンスを返却するサイトが必要です。
今回はAPIサーバを自分で設けず、JSONのレスポンスを返してくれる以下のサイトを利用します。
試しにブラウザ上で以下のURLにアクセスしてみましょう。
https://jsonplaceholder.typicode.com/users
すると以下のようにJSONレスポンスを返してくれます。
導入
まずはプロジェクトを立ち上げます。プロジェクトの設定ですが、下記記事と同じ設定にしておりますのでご参照ください。
【Nuxt】プロジェクト立ち上げ - 大ちゃんの駆け出し技術ブログ
プロジェクトを作成したら下記コマンドでaxiosをインストールします。
$ yarn add axios
ユーザ一覧ページ
ユーザ一覧ページを実装します。せっかくvuetifyを使用していうのでv-list
タグを使用してユーザ一覧を表示します。
まずusersディレクトリをpages配下に作成します。その後usersディレクトリ配下にlist.vueを作成し、以下のように記述しましょう。
<!-- pages/users/list.vue --> <template> <v-list three-line> <template v-for="user in users"> <v-list-item :key="user.id" nuxt> <v-list-item-content> <v-list-item-title v-html="user.name"></v-list-item-title> <v-list-item-subtitle v-html="user.email"></v-list-item-subtitle> </v-list-item-content> </v-list-item> </template> </v-list> </template> <script> import axios from "axios"; export default { data() { return { users: [] }; }, mounted() { axios .get("https://jsonplaceholder.typicode.com/users") .then(response => (this.users = response.data)); } }; </script>
mounted
時にユーザ一覧を返すJSONをGETでリクエストし、レスポンスをusers
に格納しています。
mounted() { axios .get("https://jsonplaceholder.typicode.com/users") .then(response => (this.users = response.data)); }
http://localhost:3000/users/listにアクセスすると以下のようなページが表示されるはずです。
ユーザ詳細ページ
続いてはユーザ詳細ページを表示させます。これは前回の記事と同じような内容です。
詳細ページを作成するためにファイル名は「_ + プロパティ名」でした。今回のユーザデータの場合、_id.vue
や_name.vue
などが作成可能です。
それでは以下のようなファイル作成してみましょう。
<!-- pages/users/_id.vue --> <template> <div> <h1>ユーザ{{ user.id }}</h1> <h2>{{ user.name }}</h2> <p>{{ user.email}}</p> </div> </template> <script> import axios from 'axios'; export default { head(){ return { title: this.user.name } }, data(){ return { user: {}, } }, mounted(){ axios.get('https://jsonplaceholder.typicode.com/users/' + this.$route.params.id) .then(response => this.user = response.data); } } </script>
mounted
時にvue-routerのパラメータと一致するユーザ情報を受け取っています。
mounted(){ axios.get('https://jsonplaceholder.typicode.com/users/' + this.$route.params.id) .then(response => this.user = response.data); }
http://localhost:3000/users/1にアクセスすると以下のようなページが表示されるはずです。
ユーザ一覧からユーザ詳細ページにアクセスできるようにしましょう。先ほどのユーザ一覧ページのファイルのtemplateタグ内を以下のようにします。
<template> <v-list three-line> <template v-for="user in users"> <v-list-item :key="user.id" nuxt <= 追加 :to="{ name: 'users-id', params: { id: user.id } }" <= 追加 >> <v-list-item-content> <v-list-item-title v-html="user.name"></v-list-item-title> <v-list-item-subtitle v-html="user.email"></v-list-item-subtitle> </v-list-item-content> </v-list-item> </template> </v-list> </template>
v-list-item
にnuxt
プロパティを追加することでリンクがnuxt-link
であることを指定します。 :to="{ name: 'users-id', params: { id: user.id } }"
は前回の記事と同じ実装方法です。
これでユーザ一覧ページから詳細ページに遷移できます。
asyncData
現状のユーザ一覧ページと詳細ページはどちらも先にページが読み込まれ、その後axiosで取得したデータを表示する実装になっています。例えば、ユーザ一覧ページの場合、先にヘッダーやナビゲーションバーなどが読み込まれて、その後にユーザ一覧が表示されます。
しかし、二度表示される実装はあまりきれいではありません。ユーザ一覧も同時に表示させたいところ。
そこで使用するのがasyncDataプロパティです。
asyncDataはNuxtのライフサイクルの一つです。レンダリングされる前に外部APIからのデータを取得することができるようです。
Vue.jsではこのライフサイクルがないため、mounted時にAPIデータを取得するしかなく、ページ表示とずれたタイミングで取得データを表示してしまいます。しかし、asyncDataを使用すればページを表示する前にデータを取得することができるので一度の表示で完結します。
ちなみに下記のように記載するようです。見た目がdataプロパティに似ていますね。
asyncData() { return axios .httpリクエスト(url) .then(response => { return { データ名: response.data }; }); }
asyncDataでユーザ一覧ページ
百聞は一見にしかず。まずはユーザ一覧ページを以下のように変更します。
<template> <v-list three-line> <template v-for="user in users"> <v-list-item :key="user.id" nuxt :to="{ name: 'users-id', params: { id: user.id } }" >> <v-list-item-content> <v-list-item-title v-html="user.name"></v-list-item-title> <v-list-item-subtitle v-html="user.email"></v-list-item-subtitle> </v-list-item-content> </v-list-item> </template> </v-list> </template> <script> import axios from "axios"; export default { asyncData() { return axios .get("https://jsonplaceholder.typicode.com/users/") .then(response => { return { users: response.data }; }); } }; </script>
これによりデータを取得した後にページが表示されるようになりました。
context
ユーザ一覧ページと同じように既にあったmoutedを置換する形で実装することはできません。asyncDataのライフサイクル時にthisにアクセスすることができないからです。
asyncData は pages でのみ使用可能で、このフック内では this にアクセスすることはできません。
ではどうするのかというとコンテキストを使用します。
context は、Nuxt から Vue コンポーネントに追加のオブジェクト/パラメータを提供し、asyncData、fetch、plugins、middleware、nuxtServerInit のような特別な Nuxt ライフサイクル内で使用できます。
contextの中身を確認するためにconsole.logで出力してみましょう。
<!-- pages/users/_id.vue --> <template> <div></div> </template> <script> import axios from "axios"; export default { async asyncData(context) { console.log(context); } }; </script>
するとコンソールに膨大なデータが格納されていることがわかります。
これを使用して詳細ページを表示させます。
asyncDataでユーザ詳細ページ
以下のように書き換えましょう。
<!-- pages/users/_id.vue --> <template> <div> <h1>ユーザ{{ user.id }}</h1> <h2>{{ user.name }}</h2> <p>{{ user.email }}</p> </div> </template> <script> import axios from "axios"; export default { async asyncData(context) { const response = await axios.get( "https://jsonplaceholder.typicode.com/users/" + context.params.id ); return { user: response.data }; } }; </script>
こちらも一度にページが表示されるようになりました。