こんにちは、あかしぃです。
自分は本業、副業でVue.js(Nuxt.js)を使っています。
Vue.jsはReact.jsに比べると初心者でもとっつきやすい印象があり、自分の場合もReact.jsの独学は挫折しましたが、Vue.jsは独学でもなんとかなりました。
ただ、Vuex、いわゆるstoreの使い所は本当に難しいな。。。と感じていて、今でも試行錯誤しながら実装しています。(ベストプラクティスのようなものが公開されていない)。
そこで、自分のVuexの使いドコロについて以下で解説していこうと思います。Vuexの存在は知っているけど、いまいち使うタイミングがわからない・・・という人の参考になれば幸いです。
目次
まず、Vuexを使うことにどんなメリット、デメリットがあるのかです。
主に体験談ベースになるので恐縮ですが、メリットとしては以下のようなものがあると感じています。
コンポーネントの親子関係が複雑になると、それだけ状態管理が大変になります。たとえば親の持つdataを孫から更新しようとすると、子を挟んでemitを伝達することになり、このemitはどのコンポーネントのイベントを発火させるのか、というのが不明確になります。
また、子コンポーネント間の通信を行うには、子からemit → 親から違う子へpropという記述になり、dataが増えるにつれ、カオスになっていくのは避けられないような気がします。
よほど小さいアプリケーションならイベントバスでクリアできると思いますが、結局アプリが大きくなってきたときにイベントバスでは管理できなくなるでしょうから、それなら最初からVuexでいいのでは・・・ということになります。
次にVuexのデメリットについて。
Vuexを導入すると、storeディレクトリを作ることになり、その配下に数多くのファイルを作成することになります。結果、管理すべきファイル量、コード量が増えてしまいます。
あともう一つ良く聞くのが、Vuexは型安全の面で不安があるということ。自分はTypeScriptをそこまで使ったことがないので、このデメリットについてはあまりよくわからないのですが・・・。
ただ、TypeScriptの導入がどんどん盛んになっていることからすると、このデメリットはより大きくなっていくのかも、とは思います。
最初に書いたように、Vuexのベストプラクティスのようなものはまだ公開されていないです(自分で調べた限り)
なので、自分の使い方がベストプラクティスという保証はどこにもありません。むしろ、アンチパターンだったりするかも・・・。ということで、あくまで一つの参考として捉えてもらえると幸いです。
子 ← 親 → 子のようなコンポーネント構造をしていて、子コンポーネント間で同一のdataを使う場合はVuexを使います。具体例はこんな感じ。
Parent.vue
<template>
<div class="form">
<form />
</div>
<div class="message">
<message />
</div>
</template>
<script>
import Form from '@/components/Form.vue'
import Message from '@/components/Message.vue'
export default {
components: {
Form,
Message
}
}
</script>
FormコンポーネントとMessageコンポーネントを持つ親コンポーネントです。
Formコンポーネントはmessageをinputする役割を持ち、Messageコンポーネントでは入力されたmessageを表示させます。
この場合、Vuexを用いてFormコンポーネントでstate.messageを更新し、Messageコンポーネントでmessageをgettersで取得し、表示させる感じです。
このくらいの規模なら親コンポーネントにmessageをdataとして持たせ、emitとpropでそれらを更新、管理しても問題ないと思いますが、孫コンポーネントが登場したり、親コンポーネントと子コンポーネント間で共有するdataが増えてくると、メンテナンスが大変なことになります。
それなら最初からVuexで管理してしまえば、どれだけdataが増えようともその管理は基本的にstoreが担ってくれるので、コンポーネントファイルのメンテナンスを容易に保てます。
こちらも具体例を出すとこんな感じです。
Parent.vue
<template>
<div class="btn">
<button @click="openModal">Open</button>
</div>
<div class="modal">
<modal
message="message"
@close="closeModal" />
</div>
</template>
<script>
import Modal from '@/components/Modal.vue'
export default {
components: {
Modal
},
data() {
return {
message: 'Hello!',
showModal: false
}
},
methods: {
openModal() {
this.showModal = true
},
closeModal() {
this.showModal = false
}
}
}
</script>
この親コンポーネントは子にモーダルコンポーネントを持っています。
そして子コンポーネントから伝達されるのはshowModalというdataを変更したい!という命令だけです。
これならわざわざVuexを使う必要なく、素直にcloseイベントをemitすれば、それで十分かなと思います。
また、親から渡したいdataもmessageのみで、このmessageはモーダルコンポーネント以外では使われていませんから、直接propとして渡してあげればいいんじゃないかなと。
非常にシンプルな例だったので、ピンと来ない人もいるかもしれませんが、「子コンポーネント間でdataを共有したいときはVuexを使う」ということを頭に置いておけば、それなりに体裁の整ったstoreになるんじゃないかなと思います。
ただ、Vuexそのものを使わないという選択肢もあるので、まずはアプリの規模などを考慮して、Vuexを導入するかどうか検討することからスタートするのがいいかなと思いますね。
April 07, 2019 - posted by akashixi