LoginSignup
12
7

More than 1 year has passed since last update.

Nuxt.jsのasyncDataをComposition APIで

Last updated at Posted at 2020-09-03

前回の記事から続いて、Nuxt.js周りの実験中です。

vue3で正式導入予定のcomposition-apiをNuxt.jsで試してみました。

nuxtjs/composition-api のインストール

Nuxt.js用のcomposition-apiをインストール。
※ 9/3時点でv0.12.2とバージョンも低くこれから色々変わっていく可能性があるので注意です。

$ npm install @nuxtjs/composition-api --save

nuxt.config.js に設定追加

buildModulesオプションに追記

nuxt.config.js
{
  buildModules: [
    '@nuxtjs/composition-api'
  ]
}

jest用の設定を追加

※ この記事では、jestについては書かないのですが、今後書くので一応。

jest.config.js
moduleNameMapper: {
  '@nuxtjs/composition-api': '@nuxtjs/composition-api/lib/cjs/entrypoint.js',
},

composition-apiの形式に既存のコンポーネントを書き換え

Nuxt.js + buefyでインストールした場合に
デフォルトで作成されている、components/Card.vueを以下のように書き換えます。

components/Card.vue
<template>
  <div class="column">
    <div class="card">
      <header class="card-header">
        <p class="card-header-title has-text-grey">
          {{ state.card.title }}
        </p>
      </header>
      <div class="card-content">
        <div class="content has-text-centered">
          <b-icon :icon="state.card.icon" size="is-large" type="is-primary" />
        </div>
      </div>
      <footer class="card-footer">
        <div class="card-footer-item">
          <span v-html="state.card.content"></span>
        </div>
      </footer>
    </div>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, reactive } from '@nuxtjs/composition-api'

export default defineComponent({
  props: {
    title: {
      type: String,
      required: true,
    },
    icon: {
      type: String,
      required: true,
    },
    content: {
      type: String,
      required: true,
    },
  },
  setup(props) {
    const state = reactive({
      card: computed(() => props),
    })

    return { state }
  },
})
</script>

storybook でコンポーネントの確認

storybookで作成したコンポーネントのpropsの書き換えなどが正常に動作するかを確認します。
Controls addonを使ってpropsの書き換えができるようにしました。

components/Card.stories.ts
import Card from './Card.vue'

export default {
  title: 'Card',
  argTypes: {
    title: {
      name: 'title',
      defaultValue: 'Free',
      control: {
        type: 'text',
      },
    },
    icon: {
      name: 'icon',
      defaultValue: 'github',
      control: {
        type: 'select',
        options: [
          'github',
          'cellphone-link',
          'alert-decagram',
          'arrange-bring-to-front',
        ],
      },
    },
    content: {
      name: 'content',
      defaultValue: '<a href="https://github.com/relishable">github</a>',
      control: {
        type: 'text',
      },
    },
  },
}

export const Normal = (args: any, { argTypes }: { argTypes: any }) => ({
  components: { Card },
  template:
    '<card :title="title" :icon="icon" :content="content"></card>',
  props: Object.keys(argTypes),
})

storybookを起動して動作確認

$ npx nuxt storybook

compostion-storybook.gif

pages以下で非同期データを取得して、画面表示してみる

今回のメインとなるところ。
今まで、asyncDataメソッドでやっていた非同期データ取得をcomposition-apiでやってみました。

pagesに以下のcard.vueというのを作り、非同期データ用にstatic/json/data.jsonを読み込んでます。

nuxtjs/composition-apiが用意してくれている

  • useContext
  • useAsync
  • useMeta

を使ってやってみました。

pages/card.vue
<template>
  <section class="section">
    <div class="columns">
      <template v-if="state.isLoading">読込中....</template>
      <template v-else>
        <card
          :title="card.title"
          :icon="card.icon"
          :content="card.content"
          :key="card.title"
          v-for="card in state.cards"
        >
        </card>
      </template>
    </div>
  </section>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  useAsync,
  useContext,
  useMeta,
} from '@nuxtjs/composition-api'
import Card from '../components/Card.vue'

export default defineComponent({
  name: 'Cards',
  head: {},
  components: {
    Card,
  },
  props: {},
  setup() {
    const { app } = useContext()
    const state = reactive({
      cards: [],
      isLoading: true,
    })

    useAsync(async () => {
      state.cards = await app.$axios.get('/json/data.json').then((res: any) => {
        return res.data.cards
      })
      state.isLoading = false
    })

    useMeta({ title: 'カード一覧' })

    return { state }
  },
})
</script>

起動して動作確認

$ npm run dev

アクセスすると一瞬、読み込み中....が表示されたあとカード一覧が表示されました。

スクリーンショット 2020-09-04 0.25.25.png

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7