Mobile Factory Tech Blog

技術好きな方へ!モバイルファクトリーのエンジニアたちが楽しい技術話をお届けします!

Vue.observable でエラーの状態管理を行う

こんにちは、ブロックチェーンチームでソフトウェアエンジニアをしている id:odan3240 です。

ページをまたぐエラーを制御したい場合、グローバルな状態管理を行えるVuex が選択肢に上がるかと思います。しかし、Vue.js 2系に対応する 3系の Vuex は公式の TypeScript サポートがなく TypeScript と相性が悪いことが知られています。エラー状態管理のような規模の小さいものなら Vue.observable を利用すれば良いのでは?と考え実装してみたところ、いい感じになったので紹介します。

前提知識

Vue.observable とは

Vue.observable は Vue.js 2.6 から追加された API です。この API はオブジェクトをリアクティブにすることができます。コンポーネントの data 関数の返り値がリアクティブになるのと同じ仕組みです。

jp.vuejs.org

Vue.js におけるエラーハンドリング

Vue.js では処理されていない例外が検知された場合、Vue.config.errorHandler に登録されている関数を呼び出します。つまり、ここに関数を登録すれば独自のエラー処理を実装することができます。

jp.vuejs.org

Vue.js のプラグイン

Vue.js のプラグインを使用することで、Vue のインスタンス、つまり this にプロパティを生やすことが可能です。プラグインはアプリケーションの初期化時に呼び出されるようにする必要があります。

jp.vuejs.org

実装例

今回紹介する実装例は以下のリポジトリに置いています。

github.com

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 を使ったサンプルは日本語ではあまりヒットしなかったので、今回記事にしてみました。