Vue.jsで複数のコンポーネントを作っていると、同じデータを別のコンポーネントで使いたくなることはありませんか?
まさに先日ちょっとした機能を実装している際に調べたので、ご紹介していきます。
Vuex
真っ先に思いついたのは、Vuex です。
Vue.jsの状態管理ライブラリとしてはデファクト的な立ち位置で、 とりあえずVuexを入れておけば大丈夫という印象があります。
ですが、今回実装していた機能はSPAではなく、既存ページに部分的にVue.jsを利用するようなモノでした。
複雑な親子コンポーネントもなく、Vuexでは機能が多すぎるので、もっとシンプルな方法は無いかなーと考えていました。
ストアパターン
Vue.jsのドキュメントを読んでいると、 ストアパターンという状態管理の実装方法が紹介されていました。
今回は、兄弟コンポーネントに共通して利用しているデータがあり、それぞれのコンポーネントで そのデータの変更をトリガーにして、APIからデータを取得したりするような要件でした。
複雑な状態操作は行っておらず、データを変更すると処理が1つ実行される程度です。
なので、データの状態だけを管理できればよく、データの操作を統一するような実装は不要でした。
公式ドキュメントでも紹介されていた 単純なストアパターン でのデータ共有で問題なく実装が完了し、リリースできました。
実装例
簡単な例で ストアパターンを使ってみます。 以下のような例題があったとして進めていきます。
AさんとBさんはとても仲良しで、いつも同じ色の服をおそろいで着ています。
3種類の色の中から、どれを選んでもAさんとBさんが同じ色の服を着ているようにしてください。
イメージとしては、こんな感じです。
ストアパターンを導入する前は、このようなコードでした。
<body>
<main>
<section id="a">
<h2>Aさん</h2>
<ul>
<li v-for="c in colors">
<label>
<input type="radio" name="color-a" v-model="color" v-bind:value="c">
{{ c }}
</label>
</li>
</ul>
</section>
<section id="b">
<h2>Bさん</h2>
<ul>
<li v-for="c in colors">
<label>
<input type="radio" name="color-b" v-model="color" v-bind:value="c">
{{ c }}
</label>
</li>
</ul>
</section>
</main>
<script>
new Vue({
el: '#a',
data: {
color: '',
colors: [
'オレンジ',
'ピンク',
'ホワイト',
],
},
});
new Vue({
el: '#b',
data: {
color: '',
colors: [
'オレンジ',
'ピンク',
'ホワイト',
],
},
});
</script>
</body>
AさんコンポーネントとBさんコンポーネントがあり、それぞれに色の状態を持っています。
Vue.jsでは兄弟コンポーネント間でのデータ共有はサポートされていないため、Vuexやストアパターンを利用する必要があります。
ストアパターン実装後のコードです。 HTMLに変更は無いのでJavaScriptだけを載せています。
<script>
// 状態を管理するためのオブジェクト
const store = {
color: '',
colors: [
'オレンジ',
'ピンク',
'ホワイト',
],
};
new Vue({
el: '#a',
// AさんとBさんで同じオブジェクトを利用する
data: store,
});
new Vue({
el: '#b',
// AさんとBさんで同じオブジェクトを利用する
data: store,
});
</script>
store というオブジェクトを2つのコンポーネントで使うようにすることで、コンポーネント間で状態を共有できます。
まとめ
単純にデータを共有したいだけであれば今回紹介した ストアパターン で十分ではないでしょうか?
ストアパターンで実装した後に複雑になってきた場合に、やっと Vuex を導入するか検討する、という流れでもいいのではないかと思います。
とりあえずライブラリを導入するのではなく、必要最小限の機能を実装し、必要になってからライブラリの導入を検討する方が、実装スキルも身につくのではないでしょうか。