グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



Vue3の非同期コンポーネントを使ってみる

皆様、いかがお過ごしでしょうか。

今回はVue3の非同期コンポーネントがどんなものか使いながら理解していきたいと思います。

インストール

筆者の環境は以下の通りです。

$ node -v
v22.5.1
$ npm -v
10.8.2

Viteで開発環境を構築していきます。ESLintとPrettierのみ入れます。

$ npm create vue@lateset

> npx
> create-vue

Vue.js - The Progressive JavaScript Framework

✔ Project name: … asyncComponent
✔ Package name: … asynccomponent
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
? Add Vue DevTools 7 extension for debugging? (experimental) › No / Yes

$ cd asyncComponent
$ npm install
$ npm run format
$ npm run dev

生成されたディレクトリやファイルで今回不要な以下を削除します。

  • src/componentsの中のディレクトリとファイル一式
  • src/App.vueの内容

初期表示画面の準備

以下の画像のような、海外の著名人の名言をボタンで切り替えて表示できるような画面を作ります。

▼初期表示画面

コードは以下の通りです。

<!-- src/App.vue -->

<script setup>
import PersonOne from './components/PersonOne.vue'
import PersonTwo from './components/PersonTwo.vue'
import PersonThree from './components/PersonThree.vue'
import { ref } from 'vue'

const pageNum = ref(1)
</script>

<template>
  <h1>海外の著名人の名言集</h1>

  <PersonOne v-if="pageNum === 1" />
  <PersonTwo v-if="pageNum === 2" />
  <PersonThree v-if="pageNum === 3" />

  <button @click="pageNum = 1">1</button>
  <button @click="pageNum = 2">2</button>
  <button @click="pageNum = 3">3</button>
</template>
<!-- src/components/PersonOne.vue -->

<template>
  <p>
    1. Things may come to those who wait, but only the things left by those who hustle.<br />(Abraham
    Lincoln)
  </p>
</template>
<!-- src/components/PersonTwo.vue -->

<template>
  <p>
    2. All your dreams can come true if you have the courage to pursue them. <br />(Walt Disney)
  </p>
</template>
<!-- src/components/PersonThree.vue -->

<template>
  <p>3. Action is the foundational key to all success. <br />(Pablo Picasso)</p>
</template>

基本的な使い方

参考:非同期コンポーネント

準備ができた状態で、ブラウザをリロードして、デベロッパーツールの「Network」タブで確認すると、全ての名言コンポーネントが一括でロードされています。

▼リロード後の初期表示画面

本来初期画面の表示時にPersonTwo.vuePersonThree.vueは不要です。これらはそれぞれのボタンをクリックされたタイミングでロードされて表示されればいいですよね。

そこで非同期コンポーネントを使って以下のように書き替えます。

<!-- src/App.vue -->

<script setup>
import PersonOne from './components/PersonOne.vue'
import { defineAsyncComponent } from 'vue'
import { ref } from 'vue'

const PersonTwo = defineAsyncComponent(() => import('./components/PersonTwo.vue'))
const PersonThree = defineAsyncComponent(() => import('./components/PersonThree.vue'))

const pageNum = ref(1)
</script>

<template>
  <h1>海外の著名人の名言集</h1>

  <PersonOne v-if="pageNum === 1" />
  <PersonTwo v-if="pageNum === 2" />
  <PersonThree v-if="pageNum === 3" />

  <button @click="pageNum = 1">1</button>
  <button @click="pageNum = 2">2</button>
  <button @click="pageNum = 3">3</button>
</template>

再度ブラウザをリロードして、デベロッパーツールの「Network」タブで確認すると、PersonOneコンポーネントのみロードされています。

▼再リロード後の初期表示画面

ボタンをクリックして名言2を表示させると、そのタイミングでPersonTwoコンポーネントがロードされていることが分かります。名言3も同じくです。

▼ボタン2をクリック

▼ボタン3をクリック

ローディングとエラーの状態

参考:非同期コンポーネント

ローディングの状態

例えば、通信環境が悪い状態だと、ボタン1からボタン2に切り替えたタイミングで何も表示されない状態になってしまいます。「Now Loading…」等の文言を表示できたら分かりやすいですよね。

デベロッパーツールの「Network」タブの「No throttling」を3GやSlow4Gに変更すると通信速度を遅い状態を検証できます。以下の記事を参考にぜひ試してみてください。不安定な通信環境でWebサイトがどう表示されるかをシミュレートする方法 | ワードプレステーマTCD

▼通信環境が悪い状態でPersonTwoコンポーネントがロードされるまで何も表示されない

非同期コンポーネントの読み込み中に使用するローディングコンポーネントを定義します。

<!-- src/components/NowLoading.vue -->

<template>
  <p>Now Loading...</p>
</template>
<!-- src/App.vue -->

<script setup>
import PersonOne from './components/PersonOne.vue'
import NowLoading from './components/NowLoading.vue'
import { defineAsyncComponent } from 'vue'
import { ref } from 'vue'

const PersonTwo = defineAsyncComponent({
  loader: () => import('./components/PersonTwo.vue'),
  delay: 200,
  loadingComponent: NowLoading,
})
const PersonThree = defineAsyncComponent({
  loader: () => import('./components/PersonThree.vue'),
  delay: 200,
  loadingComponent: NowLoading,
})

const pageNum = ref(1)
</script>

<template>
  <h1>海外の著名人の名言集</h1>

  <PersonOne v-if="pageNum === 1" />
  <PersonTwo v-if="pageNum === 2" />
  <PersonThree v-if="pageNum === 3" />

  <button @click="pageNum = 1">1</button>
  <button @click="pageNum = 2">2</button>
  <button @click="pageNum = 3">3</button>
</template>

通信状態が悪い状態でボタン2をクリックすると、指定したNowLoadingコンポーネントが表示されています。その後少ししてPersonTwoコンポーネントが表示されます。

ローディングコンポーネントが表示されるまでに、デフォルトで 200msの遅延を設定しています。これは、高速なネットワークではローディング状態が短く、置き換えが速すぎて、ちらつきのように見えてしまうからです。

NowLoadingコンポーネントが表示される

エラーの状態

ボタン2をクリックする直前で例えば通信が切断された場合にエラーのコンポーネントを表示することもできます。

<!-- src/components/ErrorComp.vue -->

<template>
  <p>Error! Something Wrong.</p>
</template>
<!-- src/App.vue -->

<script setup>
import PersonOne from './components/PersonOne.vue'
import NowLoading from './components/NowLoading.vue'
import ErrorComp from './components/ErrorComp.vue'
import { defineAsyncComponent } from 'vue'
import { ref } from 'vue'

const PersonTwo = defineAsyncComponent({
  loader: () => import('./components/PersonTwo.vue'),
  loadingComponent: NowLoading,
  errorComponent: ErrorComp,
  timeout: 3000
})
const PersonThree = defineAsyncComponent({
  loader: () => import('./components/PersonThree.vue'),
  loadingComponent: NowLoading,
  errorComponent: ErrorComp,
  timeout: 3000
})

const pageNum = ref(1)
</script>

<template>
  <h1>海外の著名人の名言集</h1>

  <PersonOne v-if="pageNum === 1" />
  <PersonTwo v-if="pageNum === 2" />
  <PersonThree v-if="pageNum === 3" />

  <button @click="pageNum = 1">1</button>
  <button @click="pageNum = 2">2</button>
  <button @click="pageNum = 3">3</button>
</template>

リクエストが長すぎる場合にエラーコンポーネントを表示するために、timeout を指定することもできます。

▼ボタン2をクリックする直前でオフラインになった場合にErrorCompコンポーネントが表示される

終わりに

いかがでしたでしょうか。

非同期コンポーネントを利用することで、初期表示時のパフォーマンスが向上する可能性があると感じました。
また、読み込み中に「読み込んでいますよ~」と表示することで、ユーザーフレンドリーになるとも思いました。

今後も引き続き、Vue3を使って気づいた点をまとめていければと思います。

では、また。

この記事を書いた人

KJG
KJGソリューション事業部 システムエンジニア
大学4年時春に文系就職を辞め、エンジニアになることを決意し、独学でRuby、Ruby on Railsを学習。
約1年間の独学期間を経てアーティスへWebエンジニアとして入社。現在はWebエンジニアとして、主にシステムの開発・運用に従事している。
抽象的なもの、複雑なものを言語化して文章にするのが好きで得意。
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします