Vue3で非同期処理を利用して楽天APIから本のデータを取得する
楽天APIを叩く
楽天APIには初期設定が必要ですが、それは割愛。
JavaScriptで楽天APIから本のデータを取得する
JavaScriptでAPIからデータを取得するには、一般的に非同期関数を利用します。
楽天ブックス総合検索APIから、 キーワードに「JavaScript」を指定したAPIを呼び出してみます。
【ハンズオンJavaScript】非同期処理で気象庁のAPIから天気予報データを取得するで書いたように、
難しいことは考えず、非同期処理のfetch
にawait
キーワードをつけて、それを包む関数にasync
キーワードを追加します。
const rakuten_book_api = "楽天ブックスの本からJavaScriptが名前に含まれている本を検索するAPIのurl" const getData = async (url) => { const response = await fetch(url); const data = await response.json() return data } const book_data = getData(rakuten_book_api) console.log(book_data)
楽天ブックスAPIから取得できるデータの中身はこんな感じで、
Vue.jsから楽天APIで本のデータを取得する
上記のことをvue.jsで応用します。
サンプルとしてBooksコンポーネントを作り、その中で楽天ブックスAPIを叩いてみました。
vue.jsのcreated
または、mounted
にfetchメソッドを含ませることで
APIからデータを取得できます。
違いについてはこちらが参考になりますが、少し難しいので悩むならmountedにしとけば良いんじゃないかな(雑)。
Vuejs APIアクセスはcreatedとmountedのどちらで行う?
APIからの取得データには本の画像が入っているので、v-bind
で、画像のurlを設定しています。
Book.vue
<template> <div> <h2>{{ book_title }}</h2> <img v-bind:src="book_image" alt=""> </div> </template> <script> export default { name: "Book", data: () => ({ book_title: "", book_image: "" }), async mounted() { const url = '楽天ブックスAPIのアドレス' const response = await fetch(url); const data = await response.json() console.log(data.Items[0]) const first_item = data.Items[0].Item this.book_title = first_item.title this.book_image = first_item.largeImageUrl } }; </script>
APIから取得したデータ全てをv-forを利用して表示する
APIから取得してv-for
で分解して利用することを考えます。
こういったAPIから取得したデータはオブジェクトを複数持った配列
という形で流れてくることが頻繁にあります。
そのため、データが格納された配列を分解し各コンポーネントにオブジェクトを渡す処理が、アプリケーションを作成する際には頻出します。この処理の流れはぜひマスターしてください。
まず、APIにアクセスする処理を親のApp.vueコンポーネントに移し、v-for
で分解し、子のBookコンポーネントではprops
として受け取ります。
App.vue
<template> <div class="container"> <Book v-for="book_data in book_list" v-bind:book_data="book_data" v-bind:key="book_data" /> </div> </template> <script> import Book from "./components/Book.vue"; export default { name: "App", components: { Book, }, data: () => ({ book_list: "", }), async created() { const url = "楽天ブックスAPIのアドレス"; const response = await fetch(url); const data = await response.json(); this.book_list = data.Items; }, }; </script> <style > .container { display: grid; grid-template-columns: 1fr 1fr 1fr; width: 450px; } </style>
Book.vue
<template> <div style="display: flex"> <div style="width:300px; margin:10px;"> <h3>{{ book_title }}</h3> </div> <img v-bind:src="book_image" alt="" style="margin:10px"/> </div> </template> <script> export default { name: "Books", props: { book_data: Object, }, data: () => ({ book_title: "", book_image: "", }), mounted() { this.book_title = this.book_data.Item.title; this.book_image = this.book_data.Item.largeImageUrl; }, }; </script>