I just started using vuex with vue. I do (roughly) understand the docs. I have a specific issue for which I am not sure whether I should use vuex and if so how to go about.
I have an app in which mapbox map(s) are omnipresent in various layouts and components etc. As I will be making several vue single file components but are working with one same instance of a mapbox map I think it makes sense to have the mapbox map initiated and managed in the vuex store. So e.g. when I change the map layout or something else, it will be reflected in all components.
When I continue in this direction I am puzzled by a couple of things:
- The map is not just a variable/ array, but an instance of the mapbox class map. So I suppose the initial state is an empty object and then it needs to be initialized. Correct?
- The initialization is asynchronous and can only happen after the page is loaded, I suppose. That might be why my code below is not working!?
I tried following:
Made a mapboxmap module, with
mapboxmap.js
import simple from '../../components/simplestyle'
let mapboxgl = require('mapbox-gl/dist/mapbox-gl.js')
// initial state
const state = {
myMap: {},
mapLoaded: false
}
const mutations = {
loadMap (state, myMap) {
state.myMap = myMap
state.mapLoaded = true
}
}
const actions = {
loadMap (context) {
'use strict'
mapboxgl.accessToken = 'mysecretmapboxcode'
let myMap = new mapboxgl.Map({
container: 'map',
style: simple,
hash: true,
center: [-74.0073, 40.7124],
zoom: 16
})
context.commit('loadMap', myMap)
}
}
export default {
state,
mutations,
actions
}
And as component:
Maplayout.vue
<template>
<div>
<div id='map' class='map'>
</div>
</div>
</template>
<script type='text/babel'>
export default {
mounted () {
this.computed.myMapForView.set().then(() => this.computed.myMapForView.get())
},
computed: {
myMapForView: {
// getter
get: function () {
return this.$store.state.myMap
},
// setter
set: function () {
this.$store.dispatch('loadMap')
}
}
}
}
</script>
Which does not work. Any suggestions on the solution approach and specific way to do this is much appreciated.
Error message I get in the browser:
vue.runtime.common.js?d43f:433 TypeError: Cannot read property 'myMapForView' of undefined
at VueComponent.mounted (eval at 162 (0.ce2d9bf….js:21), <anonymous>:8:18)
at callHook (eval at <anonymous> (app.js:794), <anonymous>:2335:19)
at Object.insert (eval at <anonymous> (app.js:794), <anonymous>:2525:5)
at invokeInsertHook (eval at <anonymous> (app.js:794), <anonymous>:4352:28)
at VueComponent.patch [as __patch__] (eval at <anonymous> (app.js:794), <anonymous>:4508:5)
at VueComponent.Vue._update (eval at <anonymous> (app.js:794), <anonymous>:2222:19)
at VueComponent.eval (eval at <anonymous> (app.js:794), <anonymous>:2189:10)
at Watcher.get (eval at <anonymous> (app.js:794), <anonymous>:1652:27)
at Watcher.run (eval at <anonymous> (app.js:794), <anonymous>:1721:22)
at flushSchedulerQueue (eval at <anonymous> (app.js:794), <anonymous>:1539:13)
logError @ vue.runtime.common.js?d43f:433
EDIT:
After changing to this.myMapForView
from this.computed.myMapForView
I got following errormessage in browser:
vue.runtime.common.js?d43f:433
TypeError: Cannot read property 'set' of undefined
at VueComponent.mounted (eval at 162 (0.85b2be9….js:21), <anonymous>:6:22)
at callHook (eval at <anonymous> (app.js:794), <anonymous>:2335:19)
at Object.insert (eval at <anonymous> (app.js:794), <anonymous>:2525:5)
at invokeInsertHook (eval at <anonymous> (app.js:794), <anonymous>:4352:28)
at VueComponent.patch [as __patch__] (eval at <anonymous> (app.js:794), <anonymous>:4508:5)
at VueComponent.Vue._update (eval at <anonymous> (app.js:794), <anonymous>:2222:19)
at VueComponent.eval (eval at <anonymous> (app.js:794), <anonymous>:2189:10)
at Watcher.get (eval at <anonymous> (app.js:794), <anonymous>:1652:27)
at Watcher.run (eval at <anonymous> (app.js:794), <anonymous>:1721:22)
at flushSchedulerQueue (eval at <anonymous> (app.js:794), <anonymous>:1539:13)
logError @ vue.runtime.common.js?d43f:433
It seems to me is
new mapboxgl.Map()
is an asynchronous function and in vuex Actions can contain arbitrary asynchronous operations not mutations not from mutations. mutation handler functions must be synchronous.So you should do
new mapboxgl.Map()
in actions like following:Edit:
Given your mouse interactions are causing change in the state, you can have a computed property in you vue instance with getter and setter, like following:
Working Fiddle : http://jsfiddle.net/aucqteLn/
Also check: Vuex store with "strict: true" does not work