こんにちは、ブロックチェーンチームでソフトウェアエンジニアをしている id:odan3240 です。
ページをまたぐエラーを制御したい場合、グローバルな状態管理を行えるVuex が選択肢に上がるかと思います。しかし、Vue.js 2系に対応する 3系の Vuex は公式の TypeScript サポートがなく TypeScript と相性が悪いことが知られています。エラー状態管理のような規模の小さいものなら Vue.observable
を利用すれば良いのでは?と考え実装してみたところ、いい感じになったので紹介します。
前提知識
Vue.observable とは
Vue.observable
は Vue.js 2.6 から追加された API です。この API はオブジェクトをリアクティブにすることができます。コンポーネントの data 関数の返り値がリアクティブになるのと同じ仕組みです。
Vue.js におけるエラーハンドリング
Vue.js では処理されていない例外が検知された場合、Vue.config.errorHandler
に登録されている関数を呼び出します。つまり、ここに関数を登録すれば独自のエラー処理を実装することができます。
Vue.js のプラグイン
Vue.js のプラグインを使用することで、Vue のインスタンス、つまり this
にプロパティを生やすことが可能です。プラグインはアプリケーションの初期化時に呼び出されるようにする必要があります。
実装例
今回紹介する実装例は以下のリポジトリに置いています。
src/plugins/error.ts を実装する
src/plugins/error.ts
を簡略化しています。
import Vue, { PluginObject } from "vue"; export type Options = {}; // 状態の型を定義 export type State = { hasError: boolean; message: string; }; // this.$error でアクセスできるように型定義を拡張 declare module "vue/types/vue" { interface Vue { $error: State; } } // エラーの状態を Vue.observable を使って定義 const state = Vue.observable<State>({ hasError: false, message: "" }); // エラーが発生するとこの関数が呼ばれる Vue.config.errorHandler = err => { // エラーが存在することと、その内容を格納 state.hasError = true; state.message = err.message; // 3秒後にエラーの状態をクリア setTimeout(() => { state.hasError = false; state.message = ""; }, 3000); }; export const errorPlugin: PluginObject<Options> = { install(Vue) { // this.$error に state を注入 Vue.prototype.$error = state; } };
コンポーネント側
コンポーネント側の使用例を示します。src/App.vue
を簡略化しています。
<template> <div id="app"> <div> <button @click="click">click me!</button> </div> <div v-if="hasError">{{ errorMessage }}</div> </div> </template> <script lang="ts"> import Vue from "vue"; export default Vue.extend({ name: "App", methods: { click() { throw new Error("Error! yabai!"); } }, computed: { // this.$error.hasError と this.$error.message はエラーが発生すると自動的に値が変わる(リアクティブ) hasError() { return this.$error.hasError; }, errorMessage() { return this.$error.message; } } }); </script>
このような実装をしておくと、アプリケーションで発生した例外を自動的にキャッチして、リアクティブな変数 state
の状態が変更され、自動的に errorMessage
が表示されます。
まとめ
Vue.observable
を使ってエラー管理用のリアクティブな変数を用意して、Vue.config.errorHandler
で更新し、その変数に対して this 経由でアクセスする方法を紹介しました。
Vue.observable
を使ったサンプルは日本語ではあまりヒットしなかったので、今回記事にしてみました。