0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

vue.jsにてライフサイクルのcreatedで取得したデータを画面に表示する方法

Last updated at Posted at 2021-06-01

vueのライフサイクルでcreated時にapiから取得したデータを画面に表示したい

ある時、「画面にapiから取得したデータを描画したい!」と思いました。ちなみにapiから取得が失敗することもあるのでその出しわけもしたい。。。

変更前

App.vue
<template>
  <div>
    <template v-if="!errorMessage">
      <p>
        メッセージ: {{msg}}
      </p>
    </template>
    <template v-else>
      <p>
        {{errorMessage}}
      </p>
    </template>
  </div>
</template>
<script>
function apiTestFunc(value) {
  return new Promise((resolve, reject) => {
      setTimeout(() => {
        const n = value;
        if(n < 100) {
          resolve('100より小さい')
        } else {
          reject('100より大きい')
        }
      }, 1000)
    })
}
export default {
  data() {
    return {
      msg: null,
      errorMessage: ''
    }
  },
  async created() {
    await apiTestFunc(99) // 101を入れると.catchの方に入る
      .then(value => {
        this.msg = value;
      })
      .catch(error => {
        this.errorMessage = error;
      })
  }
}
</script>

そうするとapiとの通信中はメッセージが空白の状態で表示されてしまう
[画面ロード時]
スクリーンショット 2021-06-01 12.35.20.png
[1秒後]
スクリーンショット 2021-06-01 12.37.40.png

問題点

  • データがnullの状態で画面に描画されてしまっている
  • errorの条件分岐が見づらい
  • 一つのファイルが煩雑

解決方法

  • api通信中は[loading...]と表示させる
  • refを使い、共通コンポーネントからメソッドを呼び出す
  • slotを使いapiのステータスに応じて表示を使い出し分ける

変更後

App.vue
<template>
  <api-status 
    ref="apiStatus"
    :error-message="errorMessage"
  >
    <template #data>
      <p>
        メッセージ: {{msg}}
      </p>
    </template>
  </api-status>
</template>
<script>
import ApiStatus from './common/ApiStatus'
function apiTestFunc(value) {
  return new Promise((resolve, reject) => {
      setTimeout(() => {
        const n = value;
        if(n < 100) {
          resolve('100より小さい')
        } else {
          reject('100より大きい')
        }
      }, 1000)
    })
}
export default {
  components: {
    ApiStatus
  },
  data() {
    return {
      msg: null,
      errorMessage: ''
    }
  },
  async created() {
    await apiTestFunc(99) // 101を入れると.catchの方に入る
      .then(value => {
        this.msg = value;
        this.$refs.apiStatus.changeSuccess();
      })
      .catch(error => {
        this.errorMessage = error;
        this.$refs.apiStatus.changeError();
      })
  }
}
</script>

./common/ApiStatus.vue
<template>
  <div>
    <div v-if="apiStatus.isSuccess">
      <slot name="data"></slot>
    </div>
    <div v-if="apiStatus.isLoading">
      Loading...
    </div>
    <div v-if="apiStatus.isError">
      {{errorMessage}}
    </div>
  </div>
</template>
<script>
export default {
  props: {
    errorMessage: {
      required: false,
      type: String,
      default: ''
    }
  },
  data: () => ({
    /**
     * ローディング状態
     */
    apiStatus: {
      isLoading: true,
      isSuccess: false,
      isError: false,
    }
  }),
  methods: {
    /**
     * apiが成功した時
     */
    changeSuccess() {
      this.apiStatus = {
        isLoading: false,
        isSuccess: true,
        isError: false,
      }
    },
    /**
     * apiが失敗した時
     */
    changeError() {
      this.apiStatus = {
        isLoading: false,
        isSuccess: false,
        isError: true,
      }
    },
  }
}
</script>

[画面ロード時]
スクリーンショット 2021-06-01 12.47.53.png

[1秒後]
スクリーンショット 2021-06-01 12.37.40.png

こうすることでローディング状態、api通信成功、api通信失敗に応じて画面をだしけることができ、他のコンポーネントからも使うことが可能になります。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?