はじめに
REST APIのエラー時、ステータスコード及びエラーメッセージをユーザーにトーストで通知したい。
上記の記事でコンポーザブルによる実装を検討したが、2階層のデータの受け渡しをPropsで行っていることやページを遷移した際もデータを保持したいことなどを考慮し、ストアライブラリであるPiniaを用いた実装を行う。
Pinia
- Vue3のストア(Store)ライブラリでコンポーネントをまたいで状態を共有、管理できる
- データへの変更、加工処理もまとめて管理できる
- Propsでは親子関係のコンポーネント間のデータを受け渡ししかできなかったが、全てのコンポーネントでデータを共有できる
- キャラクターがかわいいね
- 以前はVuexが使われたいたが、現在はメンテナンスモードで新規機能は追加されない
前提条件
- 既にPiniaをインストール済みのプロジェクト
-
main.ts
でapp.use(createPinia())
を呼んでいる
Storeの作成
- 一意のid 'error' を指定
-
state
- データ本体
-
status
: HTTPレスポンスのステータス -
message
: HTTPレスポンスのエラーメッセージ
-
- 初期値を設定しておく
- データ本体
-
actions
- データの変更処理
-
set
: 引数としてstatus
とmessage
を受け取り更新 -
clear
: 状態を初期化
-
- データの変更処理
-
getters
- データの状態を基に計算された値を取得
-
isSet
: 現在エラーが設定されているかを判定 -
status
が0以上またはmessage
が空でない場合true
-
- データの状態を基に計算された値を取得
stores/error.ts
import { defineStore } from 'pinia'
export const useError = defineStore('error', {
state: () => ({
status: -1,
message: '',
}),
actions: {
set(status: number, message: string) {
this.status = status
this.message = message
},
},
getters: {
isSet: (state) => state.status >= 0 && state.message !== '',
},
})
コンポーネントからのStoreの利用
App.vue
<templete>
// isSetがtrueの場合トーストを表示
<div v-if="error.isSet" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<img src="..." class="rounded me-2" alt="...">
<strong class="me-auto">Bootstrap</strong>
<small>11 mins ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
Hello, world! This is a toast message.
</div>
</div>
</templete>
<script setup lang="ts">
// defineStore()の結果をインポート
import { useError } from '@/stores/error.ts'
// インポートしたuseErrorを関数として実行し、その結果を変数として格納
// 変数がStoreのオブジェクトととなる
const error = useError()
.
.
.
// REST API呼び出し部分でエラーが発生した場合ステータスとエラーメッセージをStoreにセット
error.set(res.status, res.error.message)
</script>
stateのリセット
- stateの状態を初期値に戻す場合は以下を利用できる
error.$reset()
Vue.js Devtools
- ブラウザの拡張機能でVue.js Devtoolsがインストールされていれば、開発者ツールのVueタブの中にPiniaタブがある
- ストア内の状態を確認できる