Как настроить централизованное состояние для карты mapbox в Vuex?

Я только начал использовать vuex с vue. Я (примерно) понимаю документацию. У меня есть конкретная проблема, для которой я не уверен, следует ли мне использовать vuex, и если да, то как это сделать.

У меня есть приложение, в котором карты mapbox вездесущи в различных макетах и ​​компонентах и ​​т. Д. Поскольку я буду создавать несколько компонентов с одним файлом vue, но работаю с одним и тем же экземпляром карты mapbox, я думаю, имеет смысл иметь mapbox map инициируется и управляется в магазине vuex. Так, например, когда я изменяю макет карты или что-то еще, это отразится на всех компонентах.

Когда я продолжаю двигаться в этом направлении, меня озадачивает несколько вещей:

  1. Карта - это не просто переменная / массив, а экземпляр карты классов mapbox. Итак, я полагаю, что начальное состояние - это пустой объект, а затем его нужно инициализировать. Правильный?
  2. Я полагаю, что инициализация является асинхронной и может произойти только после загрузки страницы. Возможно, поэтому мой код ниже не работает !?

Я пробовал следующее:

Создал модуль mapboxmap с

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
}

И как компонент:

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>

Что не работает. Мы очень ценим любые предложения по подходу к решению и конкретному способу решения этой проблемы.

В браузере появляется сообщение об ошибке:

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

РЕДАКТИРОВАТЬ: после перехода на this.myMapForView с this.computed.myMapForView в браузере появилось следующее сообщение об ошибке:

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

person musicformellons    schedule 23.12.2016    source источник


Ответы (1)


Мне кажется, new mapboxgl.Map() является асинхронной функцией и в vuex Действия могут содержать произвольные асинхронные операции, а не мутации из мутации. функции обработчика мутаций должны быть синхронными.

Таким образом, вы должны выполнить new mapboxgl.Map() в следующих действиях:

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
  }
}

const actions = {
  loadMap (context) {
    'use strict'
    mapboxgl.accessToken = 'mysecretmapboxkey'
    var 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
}

Изменить:

Поскольку взаимодействие с мышью вызывает изменение состояния, у вас может быть вычисленное свойство < / a> в вашем экземпляре vue с помощью получателя и установщика, как показано ниже :

computed: {
  myMapForView: {
    // getter
    get: function () {
      return this.$store.state. myMap
    },
    // setter
    set: function (newMap) {
      this.$store.commit('loadMap', newMap)
    }
  }
}

Рабочий скрипт: http://jsfiddle.net/aucqteLn/

Также проверьте: Магазин Vuex со строгим: true не работает

person Saurabh    schedule 24.12.2016
comment
Спасибо. Хорошая точка зрения. Я отредактировал свой вопрос, включая ваши комментарии. Тем не менее, все равно не работает (не показывает карту в браузере). Я включу полученное сообщение об ошибке. - person musicformellons; 24.12.2016
comment
@musicformellons Кажется, что вы где-то меняете состояние хранилища vuex, поскольку, как указано, переменные vuex могут быть изменены только через мутации. Можете ли вы добавить код, связанный с наблюдателем. - person Saurabh; 24.12.2016
comment
Я не думаю, что меняю состояние хранилища vuex из другого места в моем коде ... Похоже, что объект map есть, но он не показывает плитки. Когда я взаимодействую с мышью на канве карты, я получаю аналогичное сообщение об ошибке в браузере, поэтому сейчас у меня сложилось впечатление, что события моего взаимодействия с картой (загрузка, окончание перемещения, щелчок мышью и т. Д.) Считаются изменяющимися. состояние vuex 'без использования мутаций или действий, что, как я полагаю, имеет смысл, поскольку объект state.map изменяется. Имеет ли это смысл? И как действовать ?! - person musicformellons; 25.12.2016
comment
Я внес некоторые изменения ... См. Отредактированный код и сообщение об ошибке. Нам нужно отправлять, а не фиксировать, верно ?! Я также пропустил параметр newMap для функции, так как наша карта будет myMap, верно ?! - person musicformellons; 25.12.2016
comment
@musicformellons Просто нужно делать this.myMapForView, а не this.computed.myMapForView. - person Saurabh; 25.12.2016
comment
Изменил это и получил новое сообщение об ошибке, см. ИЗМЕНИТЬ выше. - person musicformellons; 25.12.2016
comment
После установки strict: false ваш (неотредактированный) код действительно работает, и карта отображается. Опубликуйте еще один вопрос о том, как заставить его работать с strict: true - person musicformellons; 30.12.2016