zawatech

[Vuex]do not mutate vuex store state outside mutation handlers.の解決方法

タグ
mutation errorVue.jsvuex
カテゴリ
JavascriptVue.js
Xこの記事をポストする
この記事をLINEでシェア

Vuexを最近使いはじめ、

Error: [vuex] do not mutate vuex store state outside mutation handlers.
[Vue warn]: Error in callback for watcher "function () { return this.data.$$state }": 
Error: [vuex] do not mutate vuex store state outside mutation handlers."

こんなエラーが出ました。
色々と調べていると、『初心者がよく躓くエラー』だそうです。(精進します。。)

TL;DR

let hoge = [] // 操作したいオブジェクト配列
              // this.vuex.objArr がvuexで管理されている変数
hoge = JSON.parse(JSON.stringify(this.vuex.objArr))

JSON.parse(JSON.stringify(obj))を使ってオブジェクトをコピーしましょう。

もしこれを使わずに普通に代入すると、『shallow copy』(浅いコピー)になってしまい参照元はvuexの方を見てしまうためエラーになります

これを回避するために、上記の方法で『deep copy』(深いコピー)を使うというわけですね。

これはどんなエラー?

Error: [vuex]do not mutate vuex store state outside mutation handlers.

vuexの変数なのに、直接変更しようとしたでしょ?mutation機能使って変更して!

って怒られています。

文字通り、vuexで管理している変数を直接書き換えようとした時に出るエラーです。

しかし今回私は、一回ローカル変数に代入してそいつを書き換えている。
直接vuexの変数などいじっていない。

↓のように、ローカル変数にオブジェクトの配列をコピーして使っているのだ。

let hoge = []            // 操作したいオブジェクト配列
                         // this.vuex.objArr がvuexで管理されている変数
hoge = this.vuex.objArr  // 代入
hoge[0].name = "山田花子" // コピーしたローカルの値を変更
                         // ここでエラー Error: [vuex]do not mutate vuex store...

…………

オブジェクトをコピーする、ここがキモだったのだ

エラーになる原理

vuexでオブジェクト要素を扱うときの原理です。

shallow copy(浅いコピー)

オブジェクトをコピーするときに、安直にそのまま代入してしまうと『shallow copy』(浅いコピー)になってしまいます。

shallow copyとは何かというと、コピー元とコピー先両方が同じメモリを参照している状態のことを言います。

今回のパターンでこれの何がマズいかというと、コピー元はvuexでメモリに保存されています。
これを浅いコピーして書き換えたとしても、vuexで管理されたメモリを直接書き換えようとしているのでmutationを使ってくださいと言われてしまう訳です。

deep copy(深いコピー)

では、同じメモリを参照しないようにすれば解決できそうです。

そこでオブジェクトだけでなく、メモリ上のデータも他の部分にコピーしてしまえば良いじゃないかというのが『deep copy(深いコピー)』です。

今回のパターンでは、メモリ上のデータもそっくりそのまま別のところへコピーしているのでvuexの管理下から逃れることができます。

これを使うケースはというと、入力フォームをvuexで持っていて、保存を押した時にstateに保存するケースです。
input要素に直接vuexのプロパティをバインドしてしまうと、更新するときなど何かと不便だったりします。

shallow copyとdeep copyの詳しい違い

詳しい違いについては、こちらの記事にまとめていますので、お時間のある方はぜひ読んでみてください。

https://zawatech.com/?p=326

解決方法

JSON.parse(JSON.stringify(obj))を使う

let hoge = [] // 操作したいオブジェクト配列
              // this.vuex.objArr がvuexで管理されている変数
hoge = JSON.parse(JSON.stringify(this.vuex.objArr))

vuexでオブジェクト要素を扱う時は、JSON.parse(JSON.stringify(obj))を使って代入をしましょう。

そうすることでdeep copyとなり、コピー先はコピー元のメモリを参照しないのでvuexの支配下から逃れ直接編集することができます。

Xこの記事をポストする
この記事をLINEでシェア
zawa1205

zawa1205

Qiita
GitHub
mail

webフロントエンドエンジニア