Suspenseにさわる

Suspenseとは?

コンポーネントを非同期で読み込むための機能らしい。 非同期で読み込む部分を<Suspense>でラップし、読み込むコンポーネントを<template #default>に定義し、フォールバックコンテンツを<template #fallback>に定義する

service/UserService.ts

/* eslint-disable require-jsdoc */
import axios from 'axios';

export interface IUser {
    id: number,
    name: string;
}

export class UserService {
  public static async getUsers(): Promise<IUser[]> {
    console.log('### UserService#getUsers() called.');
    const response = await axios.get('/api/v1/users/');
    const users = response && response.data && response.data.users ?
        response.data.users : [];
    return users as IUser[];
  }
  public static async getUser(id: string): Promise<IUser> {
    console.log('### UserService#getUser() called.');
    const response = await axios.get('/api/v1/users/' + id);
    const user = response && response.data ? response.data : {};
    return user as IUser;
  }
}

store/UserStore.ts

import {reactive, inject, provide} from 'vue';
import {UserService, IUser} from '@/service/UserService';

const key = Symbol();

export interface IUserStore {
    state: { users: IUser[] },
    updateState: () => void,
    updateStateIfEmpty: () => void
}

const createStore = () => {
  const state = reactive({
    users: [] as IUser[],
  });

  const updateState = async () => {
    console.log('### UserStore#updateState() called.');
    const users: Array<IUser> = await UserService.getUsers();
    state.users = users;
  };

  const updateStateIfEmpty = async () => {
    console.log('### UserStore#updateStateIfEmpty() called.');
    if (state.users.length == 0) {
      await updateState();
    }
  };

  return {
    state,
    updateState,
    updateStateIfEmpty,
  };
};

export const provideStore = () => {
  console.log('### UserStore#provideStore() called.');
  provide(key, createStore());
};

export const useStore = (): IUserStore => {
  console.log('### UserStore#useStore() called.');
  return inject(key) as IUserStore;
};

components/UserList.vue

<template lang="pug">
div
  ul
    li(v-for="user in state.users" :key="user.userId") {{user.userName}}
  button(@click="updateState") reload
</template>
<script lang="ts">
import {defineComponent} from 'vue';
import {useStore} from '@/store/UserStore';

export default defineComponent({
  name: 'UserList',
  async setup() {
    console.log('### UserList#setup() called.');
    const {state, updateState, updateStateIfEmpty} = useStore();
    await updateStateIfEmpty();
    return {
      state,
      updateState,
      updateStateIfEmpty,
    };
  },
});
</script>

views/UserListPage.vue

<template>
<div>
  <Suspense>
    <template #default>
      <UserList />
    </template>
    <template #fallback>
      <p>Loading...</p>
    </template>
  </Suspense>
 </div>
</template>

<script lang="ts">
import {defineComponent} from 'vue';
import {provideStore} from '@/store/UserStore';
import UserList from '@/components/UserList.vue';
export default defineComponent({
  name: 'UserListPage',
  components: {
    UserList,
  },
  setup() {
    provideStore();
  },
});
</script>

はまった点

はじめ<Suspense>を定義するテンプレートをpug化していたが、うまく動作しなかった・・・・pug化を止めたらちゃんと動作した