Vuex store with "strict: true" does not work

1.3k views Asked by At

When I set strict: true I get error:

vue.js:525 [Vue warn]: Error in watcher "state" 
(found in root instance)
warn @ vue.js:525
run @ vue.js:1752
update @ vue.js:1720
notify @ vue.js:584
reactiveSetter @ vue.js:814
Transform.resize @ transform.js:169
e.resize @ map.js:343
e._onWindowResize @ map.js:1204

vue.js:1756 Uncaught Error: [vuex] Do not mutate vuex store state outside mutation handlers.
    at assert (vuex.js:182)
    at Vue$3.store._vm.$watch.deep (vuex.js:714)
    at Watcher.run (vue.js:1746)
    at Watcher.update (vue.js:1720)
    at Dep.notify (vue.js:584)
    at Transform.reactiveSetter [as width] (vue.js:814)
    at Transform.resize (transform.js:169)
    at e.resize (map.js:343)
    at e._onWindowResize (map.js:1204)

When I set strict: false, or leave the line out completely, it works fine. As working in strict mode is recommended: what can I do to avoid the error? As I do not think I am mutating the store outside mutation handlers in my code!?

See behavior in this fiddle.

1

There are 1 answers

0
jian On BEST ANSWER

As I do not think I am mutating the store outside mutation handlers in my code

Although you are not mutating the store state outside mutation handlers, the mapboxgl.Map instance does.

var myMap = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v9',
  hash: true,
  center: [-74.0073, 40.7124],
  zoom: 16
})

Here you are creating an instance of a Map class that has its own state (including a reference to the DOM element) and methods. This map instance will listen for DOM events (user interaction) and update its own state, thus breaking vuex's rule.

My suggestion is that you should create a vue component for the map as others said. Since the map instance has a reference to the DOM element <div id="map">, to me it belongs to the view layer, not the store layer. Vue is a view layer framework and focuses on everything related to DOM, while Vuex is a state management library which is best for serializable application state (like JSON data) and it should be decoupled from actual DOM elements.

As for communication with other components, if it is direct parent-child relationship, you can use props/child refs and event callbacks; otherwise you can extract/copy certain state (e.g., zoom) from the map instance and save it to vuex store, or use a global event bus.

As a side note, vue comes with no guarantee that it will play well with any libraray that mutates the DOM. The user who uses such a lib is responsible for managing it, and the lifecycle hooks are the best place to do such things.