一个Vuex模块能否观察另一个Vuex模块?

16

Vuex模块能否监视其他模块的状态,并因此触发操作?

例如,让我们考虑以下情况:

store.js

import time from './store/time' ;
import position from './store/position' ;

const store = new Vuex.Store
(
    {
        modules:
        {
            time,
            position
        }    
    }
) ;

存储/时间.js

export default
{

    namespaced: true,

    state:
    {
        time: new Date()
    },

    getters:
    {
        time: (aState) => aState.time
    },

    mutations:
    {

        setTime (aState, aTime)
        {
            aState.time = aTime ;
        }

    }

} ;

存储 / 位置.js

export default
{

    namespaced: true,

    state:
    {
        positions: {}
    },

    getters:
    {
        positions: aState => aState.positions
    },

    mutations:
    {

        setPositions (aState, aPositionArray)
        {
            aState.positions = aPositionArray ;
        }

    },

    actions:
    {

        fetchPositionsAtTime ({ dispatch, commit, rootGetters }, { time })
        {
            // Fetch positions at given time from the server
            // commit('setPositions', ...)
        }

    }

} ;
理想情况下,我希望位置模块能够监听时间模块,并在时间状态发生更改时重新获取位置(即触发fetchPositionsAtTime)。
当然,我可以在setTime变异中添加一个分派来触发位置模块操作,但我认为从另一个方向(即监听)会更加优雅(因为可能需要更多的模块)。
有什么解决方案吗?(当然不能使用Vue Component,这是整个问题的关键所在)
1个回答

23

您可以使用存储实例的watch方法来监视time状态,然后在time值更改时调度fetchPositionsAtTime操作:

store.watch((state) => state.time.time, (val) => {
  store.dispatch('position/fetchPositionsAtTime', { time: val })
});

如果您不想直接监视状态,也可以像这样监视getter:

store.watch((state, getters) => getters['time/time'], (val) => {
  store.dispatch('position/fetchPositionsAtTime', { time: val })
});

这是一个链接,指向 Vuex.Store 实例的 API 文档。


下面是一个示例:

const time = {
  namespaced: true,
  state: {
    time: new Date()
  },
  getters: {
    time: (aState) => aState.time
  },
  mutations: {
    setTime (aState, aTime) {
      aState.time = aTime ;
    }
  }
};

const position = {
  namespaced: true,
  state: {
    positions: {}
  },
  getters: {
    positions: aState => aState.positions
  },
  mutations: {
    setPositions (aState, aPositionArray) {
      aState.positions = aPositionArray ;
    }
  },
  actions: {
    fetchPositionsAtTime ({ dispatch, commit, rootGetters }, { time }) {
      let value = rootGetters['position/positions'].value || 0;
      commit('setPositions', { value: ++value });
    }
  }
};

const store = new Vuex.Store({
  modules: { time, position }    
});

store.watch((state) => state.time.time, (val) => {
  store.dispatch('position/fetchPositionsAtTime', { time: val })
});

new Vue({
  el: '#app',
  store,
  methods: {
    setTime() {
      this.$store.commit('time/setTime', new Date());
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>

<div id="app">
  time: {{ $store.getters['time/time'] }}
  <br>
  position: {{ $store.getters['position/positions'] }}
  <br>
  <button @click="setTime">Change time</button>
</div>


确实是一个非常棒的解决方案,谢谢!如果观察 getter 而不是直接观察状态,这个方法也可以工作吗? - Lucas
谢谢!在我的情况下,为了使用 getters,我不得不这样做 store.watch(() => store.getters['time/time'], ...),因为 TypeScript 不允许我使用 (state, getters) 作为函数参数... - Lucas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接