Vue js Vuex TypeError: context.dispatch(...) is not a function

Vue js Vuex TypeError: context.dispatch(...) is not a function

我有秒表功能可以运行像下面这样的秒表:

Stopwatch.vue

<script>
export default {
  data() {
    return {
      time: "00:00.000",
      timeBegan: null,
      timeStopped: null,
      stoppedDuration: 0,
      started: null,
      running: false,
    };
  }
  methods: {
    start() {
      if (this.running) return;

      if (this.timeBegan === null) {
        this.timeBegan = new Date();
      }

      if (this.timeStopped !== null) {
        this.stoppedDuration += new Date() - this.timeStopped;
      }

      this.started = setInterval(this.clockRunning, 10);
      this.running = true;
    },
    clockRunning() {
      let currentTime = new Date();
      let timeElapsed = new Date(
        currentTime - this.timeBegan - this.stoppedDuration
      );
      let min = timeElapsed.getUTCMinutes();
      let sec = timeElapsed.getUTCSeconds();
      let ms = timeElapsed.getUTCMilliseconds();

      this.time =
        this.zeroPrefix(min, 2) +
        ":" +
        this.zeroPrefix(sec, 2) +
        "." +
        this.zeroPrefix(ms, 3);
    },
    zeroPrefix(num, digit) {
      let zero = "";
      for (let i = 0; i < digit; i++) {
        zero += "0";
      }
      return (zero + num).slice(-digit);
    },
  },
  mounted() {
    this.start();
  }
};
</script>

有了上面的功能,秒表就可以正常工作了,但是我想用vuex移动秒表的功能,这样我就可以更容易地从任何组件调用秒表功能。

index.js <-- 在 Vuex/store/stopwatch

export default {
  state: {
        time: "00:00.000",
        timeBegan: null,
        timeStopped: null,
        stoppedDuration: 0,
        started: null,
        running: false,
  },
    actions: {
    start(context) {
      if (context.state.running) return;
      if (context.state.timeBegan === null) {
        context.state.timeBegan = new Date();
      }

      if (context.state.timeStopped !== null) {
        context.state.stoppedDuration += new Date() - context.state.timeStopped;
            }
      context.state.started = setInterval(context.dispatch('clockRunning'), 10);
      context.state.running = true;
    },
    clockRunning(context) {
      let currentTime = new Date();
      let timeElapsed = new Date(
        currentTime - context.state.timeBegan - context.state.stoppedDuration
      );
      let min = timeElapsed.getUTCMinutes();
      let sec = timeElapsed.getUTCSeconds();
      let ms = timeElapsed.getUTCMilliseconds();

      context.state.time =
        context.dispatch('zeroPrefix')(min, 2) +
        ":" +
        context.dispatch('zeroPrefix')(sec, 2) +
        "." +
        context.dispatch('zeroPrefix')(ms, 3);
    },
    zeroPrefix(num, digit) {
      let zero = "";
      for (let i = 0; i < digit; i++) {
        zero += "0";
      }
      return (zero + num).slice(-digit);
    }
    },
  mutations: {},
  getters: {}
}

如果我运行上面的代码,我得到一个错误:

我认为错误发生在以下行:

context.state.started = setInterval(context.dispatch('clockRunning'), 10);

但是我没有发现上面一行有任何错误。

这是在移动到 vuex 之前工作的同一行:

this.started = setInterval(this.clockRunning, 10);

如何解决上面的错误?

更新 :

我在codesandbox

上做了一个演示代码

我尝试按照@Estus Flask 的建议进行更改,但错误仍然出现, 我试着像下面的代码一样改变:

setInterval(() => context.dispatch('clockRunning'), 10)

但是显示一个错误页面,该页面每秒继续增长,直到在短时间内变成数百个,错误的出现使我的 PC 变慢并消耗所有 CPU 性能到 100%。

出现如下错误:

谁能帮忙解决这个错误?

错误的意思就是它所说的,context.dispatch('clockRunning') 表达式是一个承诺,而它应该是一个函数,因为 setInterval 的第一个参数应该是一个函数。

setInterval 的第一个参数应该是一个函数。如果打算按时间间隔发送动作,则应为:

setInterval(() => context.dispatch('clockRunning'), 10)

dispatch returns 一个承诺,而不是一个功能。动作参数应作为 dispatch 个参数传递:

context.dispatch('zeroPrefix', min, 2) 

在表达式中使用 zeroPrefix 操作的结果是不正确的。一个动作作用于商店并且应该 returns 异步操作的承诺,而不是结果。结果需要从状态写入和读取。在这种情况下 zeroPrefix 不对状态进行操作,根本不应该是商店的一部分,它已被提取到辅助函数。

当时间达到 90 秒 = 1 分 30 秒时,我放了一个塞子,但你可以将其移除。只需在 'stop'.

上调用提交
 export default {
  state: {
    time: "00:00.000",
    timeStarted: null,
    timeBegan: null,
    timeStopped: null,
    stoppedDuration: 0,
    started: null,
    running: false,
    maxSeconds: 90,
    temp:{
      min: "0",
      sec: "0",
      ms: "0",
      secondsPassed: 0
    }
  },
  actions: {
    start({state, commit, dispatch}) {
      if (state.running) return;
      if (state.timeBegan === null) {
        state.timeBegan = new Date();
      }

      if (state.timeStopped !== null) {
        state.stoppedDuration += new Date() - state.timeStopped;
      }

      commit("start", {
        callback:()=>{
          dispatch("stopIfReachedMaximumSeconds");
          dispatch("clockRunning");
        }
      });
    },
    async clockRunning({state, commit, dispatch}) {
      let currentTime = new Date();
      let timeElapsed = new Date(
        currentTime - state.timeBegan - state.stoppedDuration
      );
      let min = timeElapsed.getUTCMinutes();
      let sec = timeElapsed.getUTCSeconds();
      let ms = timeElapsed.getUTCMilliseconds();

      commit("newTemp", {
        key: 'secondsPassed',
        value: parseInt(Math.abs((state.timeStarted - new Date() )/ 1000))
      });

      if (state.running) {
        await dispatch("zeroPrefix",{num: min, digit:2}).then(zeroPrefixResponse => {
          commit("newTemp", {
            key: 'min',
            value: zeroPrefixResponse
          })
        });
  
        await dispatch("zeroPrefix",{num: sec, digit:2}).then(zeroPrefixResponse => {
          commit("newTemp", {
            key: 'sec',
            value: zeroPrefixResponse
          })
        });
  
        await dispatch("zeroPrefix",{num: ms, digit:3}).then(zeroPrefixResponse => {
          commit("newTemp", {
            key: 'ms',
            value: zeroPrefixResponse
          })
        });
        state.time = state.temp.min + ":" + state.temp.sec + "." + state.temp.ms;
      }
    },
    zeroPrefix(context, payload) {
      return new Promise(resolve => {
        let zero = "";
        for (let i = 0; i < payload.digit; i++) {
          zero += "0";
        }
        resolve((zero + payload.num).slice(-payload.digit));
      });
    },

    stopIfReachedMaximumSeconds({state, commit}){
      if(state.temp.secondsPassed >= state.maxSeconds){
        console.log("REACHED MAXIMUM SECONDS");
        commit("stop");
      }
    }
  },
  mutations: {
    newTemp(state, payload){
      state.temp[payload.key] = payload.value;
    },
    addSecondPassed(state, second){
      state.temp.secondsPassed += second;
    },
    resetSecondPassed(state){
      state.temp.secondsPassed = 0;
    },
    start(state, payload){
      state.timeStarted = new Date();
      state.started = setInterval(()=>{
        payload.callback();
      }, 10);
      state.running = true;
    },
    stop(state){
      clearInterval(state.started);
      state.timeStarted = null;
      state.started = null;
      state.running = false;
      state.temp.secondsPassed = 0;
    }
  },
  getters: {}
};