現役フリーランスエンジニアが運営するテックメディア。日々の業務で得た知識を発信していきます!

  1. フロントエンド
  2. 5517 view

TypeScriptでNuxtアプリを作るチュートリアル【書籍検索システム】

最終更新日:2018/11/26

前回のページでは、プロジェクトの設定と画面構築が終わりました。それではお待ちかねロジック部分を実装していきましょう!!

Storeを作る

state, mutations,actionsを定義します。

store/index.ts

import axios from 'axios'

export const state = () => ({
  books: [],//検索された本一覧
  book: {},// 詳細表示される本
  query: '', // 検索ワード
})

// mutaions

export const mutations = {
  setBooks(state, books) {
    state.books = books
  },
  setQuery(state, query) {
    state.query = query
  },
  setBook(state, book) {
    state.book = book
  },
  clearBook(state) {
    state.book = {}
  },

}

// actions

export const actions = {
  async search({ commit , state }) {
    if(!state.query) {
      return;
    }
    const path = `https://www.googleapis.com/books/v1/volumes?q=${state.query}`;
    const response = await axios.get(path);
    if(response.data && response.data.items) {
      const books = response.data.items;
      commit("setBooks", books.slice(0,10))
    }
  },
  async fetchBook({ commit, state }, id) {
    commit("clearBook");

    // stateの中から指定されたidの本を探しあったらそれをstateにセットする
    const book = state.books.find(book => book.id == id)
    if(book != undefined) {
      commit("setBook", book)
      return
    }
    // stateの中から指定されたidの本が見つからなかったらAPIをコールする
    const path = `https://www.googleapis.com/books/v1/volumes/${id}`;
    const response = await axios.get(path);
    if(response && response.data) {
      const data = response.data;
      commit("setBook", data)
    }
  }
}

わかりにくいところはプログラムにコメントを入れましたので参考にしてください。このようにstore/配下にxxxxxx.tsというファイルを置くとNuxtがStoreを作ってくれます。便利ですね〜

コンポーネントとストアを接続する

まずはpages/index.vueからやっていきます。

<template lang="pug">
  section
    b-container
      b-row.row
        b-col
          b-form(@submit="onSubmit") //①追加
            b-input-group(size="lg")
              b-form-input(
                size="sm",
                class="mr-sm-2",
                type="text",
                placeholder="キーワードを入力してください。",
                @change="handleChange"
                :value="query"
              ) // ②追加
              b-button(size="sm",class="my-2 my-sm-0",type="submit") 検索する
        b-col
      div.cards
        book-list-item(
          v-for='book in books',
          :key='book.id',
          :book='book',
        ) //③修正
</template>

<script lang="ts">
import {
  Component,
  Vue,
} from "nuxt-property-decorator"
import { State } from "vuex-class" // ④追加
import BookListItem from "~/components/BookListItem.vue"

@Component({
  components: {
    BookListItem
  }
})
export default class extends Vue {
  @State books // ⑤追加
  @State query // ⑥追加

  // ⑦追加
  handleChange(e): void {
    this.$store.commit('setQuery', e);
  }

  // ⑧追加
  onSubmit(e): void {
    e.preventDefault();
    this.$store.dispatch('search');
  }

}
</script>
<style lang="sass">
.cards
  display: flex
  flex-wrap: wrap

.row
  padding: 8px 0
</style>

修正箇所は全てプログラム内にメモしてあります。それでは修正箇所を流れで説明していきます。

  • ②で検索ボックスのテキストが変更されるたびに⑦で追加したhandleChange関数が呼ばれStateのqueryに検索クエリが保存される

  • 検索ボタンが押されると①で追加したonSubmit関数が呼ばれsearchというActionがdispatchされる

  • ④、⑤、⑥のように変数を追加することでStateの値を参照できるようにする

  • ③のように書き換えることで本一覧が取得できる

次にcomponents/BookListItem.vueを以下のように書き換えます。

<template lang="pug">
b-card.mb-2.card(:title="title", :img-src='thumbnail', img-alt='Image', img-top='', tag='article', style='max-width: 20rem;')
  p.card-text {{description}}
  router-link(:to="'/books/' + id") 
    b-button(variant='primary') 詳細を見る
</template>

これで書籍が検索できて内容が表示されるようになったはずです!詳細画面もほぼ同じですのでサクッとやっていきましょう。

pages/books/_id.vue

<template lang="pug">
  section
    div.cards
      book-detail-item(:book="book") //追加
</template>

<script lang="ts">
import {
  Component,
  Vue
} from "nuxt-property-decorator"
import BookDetailItem from "~/components/BookDetailItem.vue"
import { State } from "vuex-class" // 追加

@Component({
  components: {
    BookDetailItem
  }
})
export default class BookDetail extends Vue {
  @State book //追加
  mounted () {
    this.$store.dispatch('fetchBook', this.$route.params.id)
  } // 追加
}
</script>

components/BookDetailItem.vue


<template lang="pug"> div.card div.thumbnail b-img(:src="thumbnail",fluid,alt="Responsive image") div.content h2 {{title}} p.card-text {{description}} </template>

以上で終了です!お疲れ様でしたーー

The following two tabs change content below.
WINDII

WINDII

WINDII(ウィンディ)は、フリーランスエンジニアが運営するテックメディアです。 日々の業務で得た知見を、皆さんに役立つコンテンツにして発信していくので応援よろしくお願いします! また、Slackで無料コミュニティも運営しています。たくさんのエンジニアが参加していて、プログラミングの相談や雑談などをしている楽しいコミュニティなので、興味ある方はぜひお気軽にご参加ください。 Slackコミュニティはこちらから
1

2

フロントエンドの最近記事

  1. Nuxt.js + Contentful。HeadlessCMSでポータルサイトを作る

  2. IOSアプリをAppStoreに公開する手順書(Ionic)

  3. IonicAcademyでIonic&Angularでのアプリ開発を学ぶ

  4. Ionic4+firebaseで認証をする方法【ログイン、ログアウト機能の実装】

  5. ハイブリッドアプリ開発チュートリアル【Ionic4+OnsenUI】

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

PAGE TOP