Vue.jsのmixinを利用して肥大化したViewModelをリファクタリングする
今回はVue.jsのmixin機能を利用して肥大化したViewModelをリファクタリングするお話です。
肥大化してしまった例
Vue.jsを利用して画面全体をVMとして扱ことはよくあると思います。具体的には画面全体を囲むHTML要素のidををコンストラクタに渡すオブジェクトのelに設定することです。
下記の例では#js-appをelとして設定しています。
<div id="js-app" class="app"> <div>野菜検索</div> <div> <input v-model="vegetableName" placeholder="野菜"> </div> <button type="button" @click="searchVegetable">野菜を探す</button> <hr> <div>果物検索</div> <div> <input v-model="fruitsName" placeholder="果物"> </div> <button type="button" @click="searchFruits">果物を探す</button> </div>
new Vue({ el: '#js-app', data: { vegetableName: 'トマト', fruitsName: 'りんご' }, methods: { searchVegetable() { alert('野菜を探す'); }, searchFruits() { alert('果物を探す'); } } });
この例では「野菜検索」と「果物検索」は相互に関係していないのにもかかわらず、それらのmethodsとdataが同じオブジェクトに含まれて初期化されていることが問題となってきます。
現状、そこまでコードの行数が多くないのですが複雑さが増してきた際に、複数の機能を一つのオブジェクトとして扱うと、どのメソッドやデータがどの機能(振る舞い)を管理しているかわかりにくくなってしまいます。
さらに、componentsとしてテンプレートを切り出すほどでもない・・・という悩みもでてきたりします。
そこでmixin
実は、Vue.jsにmixinを扱う機構がデフォルトで備わっています。そのためVMの中の一部の振る舞いを別オブジェクトとして外部に切り出してし初期化時にmixinとして埋め込むことができます。これは、mixinの本来の利用方法である汎用的な振る舞いの定義に利用できますし、今回のケースのように同一VM内での振る舞いの整理にも利用することができます。
JS部分を直してみる
こんな感じ。
const VegetableSearchable = { data() { return { vegetableName: 'トマト' } }, methods: { searchVegetable() { alert('野菜を探す'); } } }; const FruitsSearchable = { data() { return { fruitsName: 'りんご' } }, methods: { searchFruits() { alert('果物を探す'); } } } new Vue({ el: '#js-app', mixins: [VegetableSearchable, FruitsSearchable] });
methodsやcreatedなどのライフサイクルを扱うメソッドにしか適用できないのかと勘違いしていましたが、data自体もmixinに閉じ込めることができるようです。
一VMでの機能が増えてきた際には是非導入していきたいところですね。
ヽ(•̀ω•́ )ゝ✧ オラッオラッ
参考
2015.03.02 訂正
ツイッターで以下のようなコメントを貰ったのでdataを関数に変更。データのスコープを閉じ込めるためですね。 ありがとうございます!
data は関数にすべきかな。/ Vue.jsのmixinを利用して肥大化したViewModelをリファクタリングする - 俺、サービス売って家買うんだ https://t.co/uIWztWghS8
— 🐤kazuya kawaguchi🐤 (@kazu_pon) February 27, 2016
関連書籍
- 作者: 掌田津耶乃
- 出版社/メーカー: 秀和システム
- 発売日: 2016/09/16
- メディア: 単行本
- この商品を含むブログを見る
Practical Vue.js: Reactive Components for Modern Web Interfaces (English Edition)
- 作者: Daniel Schmitz
- 発売日: 2016/07/08
- メディア: Kindle版
- この商品を含むブログを見る