v-modelでstateやgettersを変更したい時に使える算出プロパティのset()関数
最終更新日: Update!!
フォームなどに入力した値がリアルタイムで変数と同期される双方向バインディングはVueの強みの一つでもあります。ただし、変数にstateを使った場合には仕様上、直接更新することができません。そこで今回はv-modelでstateを更新する方法についてまとめていきたいと思います。
テキストを入力すると出力側でも値が更新されるのが確認できます。
しかし、下記のように変数にstateを参照する場合、v-modelで更新しようとするとエラーになってしまいます。これはVueの仕様でstateの値はmutationsからのみ更新できるというルールに基づいているためです。
実際にstateの値も更新されていないのが確認できます。
そこで、v-modelでstateの値を更新する方法をいくつか見ていきましょう。
値を入力すると、mutationsを経由して、stateの値が更新されているのが確認できますね。
入力すると双方向バインディングにより、入力値が同期され、stateにはmutations経由で値が更新され、出力側にはgettersで更新されたstateの値が表示されています。
いかがでしょうか、双方向バインディングにおいては実装ケースも多いかと思いますが、stateの値を扱う場合には少し注意が必要ですね。その場合には上記の方法がとても役に立つのではないでしょうか。
v-modelを使った双方向バインディングの基本形
まずはVueで扱う双方向バインディングの基本からおさらいです。過去記事「Vue.jsで双方向データバインドを使ったサンプル」にもまとめておりますのでご参考に。 この双方向バインディングは、対象となる入力要素(inputなど)に「v-model」ディレクティブを設定し、その値に変数や関数を指定します。出力側では2重波括弧のマスタッシュ( {{ }} )でv-modelで指定した変数もしくは関数を囲みます。 【Vue】<template> <div id="app"> <input type="text" v-model="messege"> <p>入力:{{ messege }}</p> </div> </template> <script> export default { data: function() { return { messege: 'default' } } } </script>上記では、dataオプションで指定した変数の値がinputで入力した内容と同期される形になります。これが基本的な双方向バインディングの形となります。実際に実装した例を見るとこのような形になります。




v-onとdispatch()関数を使ったv-modelでのstateの更新
v-modelでstateの値を更新する方法の1つに、v-onのイベントハンドラで「dispatch()」関数でactionsを呼び出したり「commit()」関数でmutationsを呼び出すことによりstateを更新する方法があります。まずは下記のようにstateやactions、mutationsを定義していきます。 【store.js】import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { messege: 'default' // stateの初期値 }, mutations: { mutateMessege(state, payload) { state.messege = payload; } }, actions: { commitMessege(store, payload) { return store.commit('mutateMessege', payload) } }, getters: { getStateMessege: (state) => state.messege } })stateには初期値を、mutationsにはstateの値を引数である「payload」によって更新されるように、actionsには引数である「payload」を受け取りmutationsに渡すための関数を指定します。stateの値はgettersで取得できるようにしておきます。詳しくはこちらの記事「stateの値を参照するときに使えるgettersについて」を参考に。 そして、Vueファイルの方でロジックを記述していきます。まずテンプレート側の入力要素にはv-modelディレクティブにdataオプションの変数を指定します。そしてv-onディレクティブでイベントを設定し、発火させる関数を指定します。ここではinputイベントで設定しています。必要であれば出力させる要素も用意しておきます。 【Vue】
<template> <div id="app"> <textarea v-model="messege" @input="inputText"> </textarea> <p>入力:{{ messege }}</p> <p>stateの値:{{ computedGetState }}</p> </div> </template> <script> export default { data: function() { return { messege: 'default' } }, computed: { computedGetState() { return this.$store.getters.getStateMessege } }, methods: { inputText() { // dispatch()でactionsを呼び出す、もしくはcommit()で直接mutationsを呼び出す this.$store.dispatch('commitMessege', this.messege) } } } </script>スクリプトの方では、変数をdataオプションで用意します。そしてmethodsではイベントハンドラに設定した関数を記述します。この関数内で、v-modelで指定した変数を「dispatch()」関数で定義したactionsを呼び出す形になります。dispatchの第一引数には呼び出すactionsの関数を、第二引数には受け取る変数を指定します。ちなみにactionsを経由せずに「commit()」関数で直接mutationsを呼び出してもOKです。 これでv-modelとstateが紐づけられ、双方向バインディングが実装することができました。実際のサンプルを見ていきます。デフォルトではそれぞれの初期値が表示されています。


算出プロパティのset()関数を使ったv-modelでのstateの更新
先ほどのイベントハンドラを使った方法でも実装は可能ですが、少し冗長性が感じられてしまいます。そこで算出プロパティの「set()」関数を使ってよりシンプルに実装する方法についてまとめていきたいと思います。actions、mutationsなどの定義は先程と同じなのですが、Vueの方ではよりすっきりと短いコードになります。 【Vue】<template> <div id="app"> <textarea v-model="computedGetState"> </textarea> <p>入力:{{ computedGetState }}</p> <p>stateの値:{{ computedGetState }}</p> </div> </template> <script> export default { computed: { computedGetState: { get() { // 値を返すときはgettersを指定 return this.$store.getters.getStateMessege }, set(value) { // 値の代入はdispatch()でactionsを呼び出す、もしくはcommit()で直接mutationsを呼び出す this.$store.dispatch('commitMessege', value) } } } } </script>まず、テンプレート側ではv-modelに算出プロパティのcomputedで定義した関数のオブジェクトのキーを指定します。出力する要素にも同じものでOKです。先ほどのものと比べてもかなりスッキリとしましたね。 スクリプト側では、テンプレートで指定したオブジェクトをcomputedに用意していきます。ここで「get()」関数と「set()」関数の2つを用意します。 まず、get()関数の方には、そのままgettersが返されるようにしておきます。つまり、出力される場合はgettersの値が表示されるようになります。 そして、set()関数には引数を受けてdispatch()もしくはcommit()関数でactionsやmutationsを経由してstateの値を更新するようにしておきます。つまり、値が入力されて代入する場合にはその値を受け取りstateが更新される仕組みです。ですので、set()関数には引数が必要になります。この引数にはv-modelで関連づけられた入力要素の入力値が入ります。 実際のサンプルを見ていきます。算出プロパティにあるgettersが初期値に表示されています。



いかがでしょうか、双方向バインディングにおいては実装ケースも多いかと思いますが、stateの値を扱う場合には少し注意が必要ですね。その場合には上記の方法がとても役に立つのではないでしょうか。
sponserd
keyword search
recent posts
- GSAPとvivusを使ったSVGのドローアニメーション
GSAPとvivusを使ったSVGのドローアニメーション
- GSAPでScrollTriggerプラグインを使ったスクロール固定表示アニメーションの応用
GSAPでScrollTriggerプラグインを使ったスクロール固定表示アニメーションの応用
- Shopifyでオリジナルテーマ制作やテーマカスタマイズで使えるTips #3
Shopifyでオリジナルテーマ制作やテーマカスタマイズで使えるTips #3
- Shopifyでオリジナルテーマ制作やテーマカスタマイズで使えるTips #2
Shopifyでオリジナルテーマ制作やテーマカスタマイズで使えるTips #2
- Shopifyでオリジナルテーマ制作やテーマカスタマイズで使えるTips #1
Shopifyでオリジナルテーマ制作やテーマカスタマイズで使えるTips #1
- ViteでReactとReact Routerを使ってみる
ViteでReactとReact Routerを使ってみる
- ViteでPugのコンパイル環境を導入する
ViteでPugのコンパイル環境を導入する
- ViteでMarkuplintとPrettierを使える環境を構築する
ViteでMarkuplintとPrettierを使える環境を構築する
categories