将redux-saga与setInterval一起使用 - 如何以及何时产生

时间:2017-12-31 17:16:18

标签: generator redux-saga

刚刚从thunk转移到sagas我正试图找到调用setTimeout的最佳方法,然后从该函数内调用另一个函数(在本例中为corewar.step())。这是我原来的代码,它可以按照我的预期运行。

  runner = window.setInterval(() => {

    for(let i = 0; i < processRate; i++) {
      corewar.step()
    }

    operations += processRate;

  }, 1000/60)

此代码位于saga内,我相信我应该能够在call中包装函数调用,就像我在应用程序的其他区域中所做的一样。

我已尝试将setInterval电话打包在call中并将其他所有内容保留原样,这导致step()永远不会被调用。

  runner = yield call(window.setInterval, () => {

    for(let i = 0; i < processRate; i++) {
      corewar.step()
    }

    operations += processRate;

  }, 1000/60)

我已经尝试过,保留setInterval,并将step()函数包含在调用中,并将匿名函数签名更改为function*,这也会导致step()永远不会被召唤。

  runner = window.setInterval(function*() {

    for(let i = 0; i < processRate; i++) {
      yield call([corewar, corewar.step])
    }

    operations += processRate;

  }, 1000/60)

最后,我尝试将两者都包装起来,这再次导致永远不会调用step()

  runner = yield call(window.setInterval, function*() {

    for(let i = 0; i < processRate; i++) {
      yield call([corewar, corewar.step])
    }

    operations += processRate;

  }, 1000/60)

感觉我在这里遗漏了一些东西,所以我的问题是,我是否需要在call完全包装这些功能或者这是错误的?

如果我应该将setInterval包裹在call中,那么我将如何定义一个函数作为call的参数,这也是我想要产生的putcall本身?

4 个答案:

答案 0 :(得分:8)

saga-redux文档中有一个名为“Using the eventChannel factory to connect to external events”的部分,建议使用channels

本节还提供了setInterval实施的示例:

import { eventChannel, END } from 'redux-saga'

function countdown(secs) {
  return eventChannel(emitter => {
      const iv = setInterval(() => {
        secs -= 1
        if (secs > 0) {
          emitter(secs)
        } else {
          // this causes the channel to close
          emitter(END)
        }
      }, 1000);
      // The subscriber must return an unsubscribe function
      return () => {
        clearInterval(iv)
      }
    }
  )
}

然后,您可以使用yield callyield takeEvery进行设置:

const channel = yield call(countdown, 10);
yield takeEvery(channel, function* (secs) {
    // Do your magic..
});

答案 1 :(得分:4)

const anotherSaga = function * () {
  const runner = yield call(setInterval, () => {
    console.log('yes');
  }, 1000);
  console.log(runner);
}

这对我来说非常好。在你的第二个片段中,最后只有一个),只有一个。

答案 2 :(得分:3)

这里的聚会晚了一点,但这是在传奇中设置计时器的最高搜索结果。由于sagas的性质,有一种替代解决方案。 From here.

我对此进行了修改:

function* callSelfOnTimer({ value }) {
  // Do your work here
  ...
  // If still true call yourself in 2 seconds
  if (value) {
    yield delay(2000);
    yield call(callSelfOnTimer, { value });
  }
}

答案 3 :(得分:1)

要使其正常工作,还需要添加以下内容:

const delay = (ms) => new Promise(res => setTimeout(res, ms))

function* callSelfOnTimer({ value }) {  
    // Do your work here  
    ...  
    // If still true call yourself in 2 seconds  
    if (value) {  
        yield delay(2000);  
        yield call(callSelfOnTimer, { value });  
    }  
}