Шина глобальных событий с использованием Vuex - всегда уведомляйте подписчиков - PullRequest
0 голосов
/ 03 декабря 2018

Я уже довольно давно использую шину глобальных событий в Vue - что-то вроде const bus = new Vue().Работает нормально, однако, удаление подписок может стать довольно многословным.

Допустим, я подписываюсь на событие в компоненте:

mounted() {
  bus.$on('some.event', callback)
}

Я должен был бы отслеживать обратный вызов иутилизируйте его правильно в beforeDestroy.Это можно несколько упростить, используя глобальный миксин, но, поскольку я использую <keep-alive>, я должен различать подписки, сделанные с помощью обратного вызова mounted и activated.

Так что я решил дать Vuexвыстрел в управлении этим, так как наблюдатели располагаются рамками.Я пришел с предложением ниже.

Кажется, работает нормально, пока публикуются объекты или массивы.Кажется, что примитивные данные не вызывают реактивность, несмотря на то, что они обернуты во внешний объект, то есть { data: 123 }

Я ищу альтернативные решения в отношении уведомления подписчиков.Все, что я видел до сих пор, это внутренний метод notify, который не очень безопасен в использовании.

eventstore.js

import Vue from 'vue'

const state = {
  events: {}
}

const actions = {
  publish({commit}, payload) {
    commit('publish_event', payload)
  }
}

const mutations = {
  publish_event(state, payload) {
    if(!state.events[payload.key]) {
      Vue.set(state.events, payload.key, { data: payload.data })
    } else {
      state.events[payload.key] = { data: payload.data }
    }
  }
}

const getters = {
  events: state => state.events
}

export default {
  state,
  actions,
  mutations,
  getters
}

globalmixin.js

methods: {
  publish(key, data) {
    this.$store.dispatch('publish', { key, data })
  }
}

somecomponent.vue

function mapEventGetters(eventKeys) {
  return _.reduce(eventKeys, (result, current) => {
    result[current] = function() {
      return  _.get(this, `$store.getters.events.${current}.data`)
    }
    return result
  }, {})
}
computed: {
  ...mapEventGetters(['foo_bar'])
},
watch: {
  'foo_bar'(value) {
    console.log(`foo_bar changed to ${value}`)
  }
}

Ответы [ 3 ]

0 голосов
/ 09 декабря 2018

Можете ли вы попробовать это и сообщить мне, была ли реактивность запущена в обеих этих ситуациях?

Сначала удалите эту ненужную перенос с внешним объектом и отправьте полезную нагрузку в виде простого объекта ключ / значение с требуемым ключом события иданные для этого ключа:

{
  someKey: 123
}

В качестве второго отправьте несколько вложенных данных:

{
  someKey: {
    nested: 'Value'
  }
}

Но перед этим измените код мутации следующим образом:

const mutations = {
  publish_event(state, payload) {
    // Instead of the previous code, just "patch"
    // the state.events with the payload content.
    state.events = { ...state.events, ...payload }
  }
}

И не забывайте улучшать функцию mapEventGetters, поскольку данные больше не вкладываются в свойство «data».

PS: Но лично я не понимаю, почему не следует использовать Vuex с конкретными получателями, потому что этоработает, он запускает реактивность с примитивными типами:

store / index.js

import Vue from 'vue'
import Vuex from 'vuex'

const state = {
  events: {}
}

const actions = {
  publish({commit}, payload) {
    commit('publish_event', payload)
  }
}

const mutations = {
  publish_event(state, payload) {
    state.events = { ...state.events, ...payload }
  }
}

const getters = {
  fooBar: state => state.events.fooBar || ''
}

Vue.use(Vuex)

export default new Vuex.Store({
  state,
  actions,
  mutations,
  getters
})

main.JS

import Vue from 'vue'
import App from '@/App'
import store from '@/store'

new Vue({
  store,
  render: h => h(App)
}).$mount('main')

некоторые компоненты

<template>
  <span>{{ fooBar }}</span>
</template>

import { mapGetters, mapActions } from 'vuex'

export default {
  name: 'SomeComponent',

  computed: {
    ...mapGetters(['fooBar'])
  },

  methods: {
    ...mapActions(['publish'])
  },

  created () {
    setTimeout(() => {
      publish({
        fooBar: 123
      })
    }, 3000)
  }
}
0 голосов
/ 10 февраля 2019

Этот API нарушит поток данных Vuex, который является основной концепцией Vuex.Клиенты могли бы изменять / хранить состояние хранилища повсюду в Vuex.

Честно говоря, этот путь не требуется реализовывать в Vuex, поскольку он является просто источником событий.Я предлагаю вам использовать какой-нибудь источник событий (возможно, пустой экземпляр Vue) в действиях.

export const emitter = new Vue()

export default {
  // ...

  actions: {
    // should be called when the store is initialized
    // to observe events
    observe({ dispatch, commit }) {
      emitter.$on('some-event', () => {
        commit('someEvent')
      })

      emitter.$on('other-event', () => {
        dispatch('otherEvent')
      })
    },

    // notify some event in action
    notify({ state }) {
      emitter.$emit('notify', state.someValue)
    }
  }
}

Это решает мою проблему один раз, когда я ищу в github.Мат поможет вам.Спасибо !!

0 голосов
/ 07 декабря 2018

Вы можете использовать deepCopy (например, JSON.parse(JSON.stringify())), чтобы убедиться, что данные реагируют

const mutations = {
  publish_event(state, payload) {
    if(!state.events[payload.key]) {
      state.events[payload.key] = { data: payload.data }
    } else {
      state.events[payload.key] = Object.assign({}, state.events[payload.key], { data: payload.data })
    }
    state.events = JSON.parse(JSON.stringify(state.events))
  }
}

В вышеприведенном компоненте вы прослушиваете foo_bar в наблюдателе. Vue watcher работает только с данными компонента (от data, computed или vuex).

Вы можете переопределить ваши данные как componentData, как показано ниже.Вы можете использовать mapGetters для более короткого синтаксиса:

<script>
  import { mapGetters } from 'vuex'
  export default {
    ...mapGetters(['events']),
    computed: {
      componentData () {
        const eventKeys = ['foo_bar']
        return _.reduce(eventKeys, (result, current) => {
          result[current] = function() {
            return  _.get(this, `events.${current}.data`)
          }
          return result
        }, {})
      }
    },
    watch: {
      componentData: function (newVal, oldVal) {
        ...
      }
    }
  }
</script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...