programing

Vuex를 사용하는 글로벌 이벤트 버스 - 항상 가입자에게 알림

prostudy 2022. 5. 15. 23:41
반응형

Vuex를 사용하는 글로벌 이벤트 버스 - 항상 가입자에게 알림

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

글로벌믹신js

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

일부의 구성 요소부에를 하다

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

딥카피(예: 딥카피)를 사용할 수 있음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>

이 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에서 검색할 때 내 문제를 한 번 해결한다.맷이 도와줄게고마워!!

호출Vue.set객체에서 관측자/반응도를 객체 내부의 데이터에 추가하지 않는다.이를 위해서는 부가적인 Vue가 필요하다.세트

Vue.set(state.events, payload.key, {})
Vue.set(state.events[payload.key], 'data', payload.data)

또한 이 기능을 유틸리티 함수에 포함시킬 수 있으며, 이 함수를 사용하여 데이터를 재귀적으로 설정할 수 있으며,Vue.set

이 두 가지 상황에서 모두 반응성이 발생했는지 알려주시겠습니까?

먼저 외부 객체로 불필요한 랩핑을 제거하고 원하는 이벤트 키와 이 키에 대한 데이터를 사용하여 페이로드를 단순 키/값 객체로 전송하십시오.

{
  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 기능을 향상시키는 것도 잊지 마십시오.

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

참조URL: https://stackoverflow.com/questions/53597963/global-event-bus-using-vuex-always-notify-subscribers

반응형