Leverage Copy

メモの公開場所

定数をVueの状態に持たせることを避ける

久しぶりすぎるブログ投稿なので、リハビリがてら小ネタを。。

TL;DR

Vueインスタンスの可変な状態の数はなるべく減らしたいので、 「一度値が決まったらそのコンポーネントが生存する間は不変」というような状態は、定義の仕方に気をつけよう、 という話です。

以降のサンプルコードなどはVue2のOption API + TypeScriptで説明します。

以下のようなコードがあるとします。

const message = '不変な値'

export default Vue.extend({
  data() {
    return {
      message,
      ...
    }
  },
  ...
})

「Viewにレンダリングさせたいものの、その値は最初に設定した定数であるようにしたい」ようなケースです。 本当に決まりきった定数だったら、最初からViewに放り込んでしまえばよいのですが、 アプリケーションの状態に応じて初期値を変えたり、Message Providerのような外部モジュールから取得した値をセットしたい、 という状況は割とあり得るのではないかと思います。

まずい点

ただし、このようにすると、Vueの状態である message は、Vueインスタンス内部から容易に変更できてしまいます。 チーム内の紳士協定によって不変であることを維持するのは大変ですし、また、 Vueインスタンスがそれなりに大きい場合、この message はいつ値が変わるかわからないグローバル変数のように感じられ、 将来コードを読む際に負担になってしまいます。

解決策

この場合は、インスタンス外で定数を定義し、算出プロパティの派生元として利用するのが良いです。

const message = '不変な値'

export default Vue.extend({
  computed: {
    msg() {
      return message
    },
  },
  ...
})

算出プロパティの派生元のデータは、Vueインスタンスdata オプションやVuex Storeのゲッターを用いることが主なため、 こういった用法は盲点になりやすい気がします。

備考1

注意点としては、当然ながら派生元のデータはVueに対してリアクティブなデータではないため、 該当する算出プロパティもリアクティブとはならないことでしょうか。 今回は const で定義されたプリミティブな値が派生元なので関係ないですが、そうでない場合は注意が必要になるかもしれません。

また逆に、本当ならばVueの状態として data に持たせなければならないものを、インスタンス外でミュータブルな変数として定義してしまうと、 本来破棄すべきタイミングに破棄されずに残ってしまったり、と余計に状態管理が面倒になるかもしれません。

「Vueインスタンスの状態として持つべきものはなにか?」というのを常に考える必要があると思います。

備考2

TypeScriptに詳しい場合は、ひょっとすると予め厳密にOptionの型を定義しておくことで、 readonly な状態みたいなものが作れるのかもしれないです。 ただ、できるにしてもかなり手間がかかりそうですし、overkillな印象です。

出典

みんなのVue.jsという書籍の「第2章: 状態管理パターン」という章に説明されている手法の紹介でした。 この書籍はやわらかいタイトルとは裏腹に、確かに実際の開発業務で役に立つ知識がぎゅっと詰まっている印象でした。 それでいて、文章やサンプルなどは平易なものがほとんどのため、非常に読みやすかったです。

おわりに

最近は、如何にしてVueのコードを「スリムに」できるか、に腐心しているような気がします。