Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 倾听redux传奇中商店的变化_Reactjs_Redux_Redux Saga - Fatal编程技术网

Reactjs 倾听redux传奇中商店的变化

Reactjs 倾听redux传奇中商店的变化,reactjs,redux,redux-saga,Reactjs,Redux,Redux Saga,我正在尝试创建一个redux传奇,它将监听状态中一个变量的变化。当它发生变化时,我想发送一些其他操作。这可能吗 这就是我想做的: yield takeLatest(fooAction, fetchAll); function* fetchAll() { const part = yield select(getPartOfState); if (part.flag) { yield call(listenToChange); } } function* list

我正在尝试创建一个redux传奇,它将监听状态中一个变量的变化。当它发生变化时,我想发送一些其他操作。这可能吗

这就是我想做的:

yield takeLatest(fooAction, fetchAll);

function* fetchAll() {
   const part = yield select(getPartOfState);
   if (part.flag) {
      yield call(listenToChange);
   }
}

function* listenToChange() {
   const anotherPart = yield select(getAnotherPartOfState);
   if (anotherPart === true) { // this is what I want to wait for
      // do something
   }
}

所以我基本上想等待另一部分的更改,因为最初它是false,并且在循环中只执行一次(即使多次执行
listenToChange
。这可能吗?

正如Alex在评论中提到的,监听状态更改归结为监听可能触发此状态更改的操作

take
效果可以采用各种模式将动作描述为参数,这可以帮助您做到这一点:一个动作、一组动作、一个函数等等。如果您不想将这些动作列为白名单,您甚至可以在不带参数的情况下调用
take
(如果您想更明确,可以使用字符串
'*'
),这使您有机会在每次操作后检查状态

有了这一点,一个等待某个状态具有给定值的传奇可以这样写:

function *waitForStateToHaveValue(selector, expectedValue) {
  let stateSlice = yield select(selector);
  while (stateSlice !== expectedValue) {
    yield take();
    stateSlice = yield select(selector);
  }
}

我采用了下面的模式,这正是您所描述的

它的工作原理是等待通过存储的每个操作,并重复选择器以查看特定值是否已更改,从而触发事件

签名是一个包装函数,它使您能够传递选择器和传奇。传奇必须接受上一个和下一个值。包装函数为所选值的每一次更改“移交”给传奇一次。您应该在传奇中编写逻辑,以便在重新创建时使用正常的收益率调用从包装生成器“接管”满足黎凡特条件

import{take,spawn,select}来自“redux saga/effects”
函数*selector或changesaga(选择器,saga){
let previous=收益率选择(选择器)
while(true){
const action=yield take()
const next=收益率选择(选择器)
如果(下一步!==上一步){
收益率*saga(下一个,上一个)
上一个=下一个
}
}
}
下面是一个测试示例,它在我的应用程序中定义了一个传奇。它生成一个正常的传奇,以正常的方式运行

只要状态的“focusId”值发生变化,逻辑就会运行。我的sagas执行与id对应的远程数据的延迟加载,并有机会从服务器刷新列表。请注意星号,尤其是yield*!它定义了生成器如何相互“交接”

//当非空id进入焦点时加载行
函数*focusIdSaga(){
yield*selectorchangesga(state=>state.focusId,function*(focusId,prevFocusId){
const{focusType,rows}=yield select()
if(focusType){
如果(!prevFocusId){//focusId以前是新行(空id)
//确保刷新id列表以包括保存的行
产量产卵(loadIdsSaga,focusType)
}
if(focusId){//新聚焦的行
如果(!行[focusId]){
//确保它已加载
产量产卵(loadRowSaga、focusType、focusId)
}
}
}
})
}
与@alex和@vonD相比,我个人很乐意监控状态,我觉得它的性能足够好,并且提供了一种简洁可靠的方法,不会错过您关心的更改,而不需要进行不必要的间接操作。如果您只跟踪操作,则很容易通过创建一个更改状态的操作引入错误,同时又不记得执行ad但是,如果你认为重复选择器的性能是一个问题,你可以缩小“取”的过滤器,以便只对你知道影响你正在监视的状态树的部分的某些动作做出响应。 更新

在@vonD所示方法的基础上,我以一种更简洁的方式重构了上述示例。monitorSelector()函数与传统的基于收益率的传奇流程交互,而无需包装任何内容。它提供了一种让传奇“阻塞”等待变化值的方法

function* monitorSelector(selector, previousValue, takePattern = "*") {
  while (true) {
    const nextValue = yield select(selector)
    if (nextValue !== previousValue) {
      return nextValue
    }
    yield take(takePattern)
  }
}
这是原始示例中经过测试的版本,但为新的监控状态方式进行了重构

//load row when non-null id comes into focus  
function* focusIdSaga() {
  let previousFocusId
  while (true) {
    const focusId = yield* monitorSelector(state => state.focusId, previousFocusId)
    const { focusType, rows } = yield select()
    if (focusType) {
      if (!previousFocusId) { //focusId previously new row (null id)
        //ensure id list is refreshed to include saved row
        yield spawn(loadIdsSaga, focusType)
      }
      if (focusId) { //newly focused row
        if (!rows[focusId]) {
          //ensure it's loaded
          yield spawn(loadRowSaga, focusType, focusId)
        }
      }
    }
    previousFocusId = focusId
  }
}

从理论上讲,有不同的方法可以做到这一点,但我不认为在传奇故事中倾听改变的状态在任何方面都是惯用的。难道你没有一个动作负责触发减速机中另一部分状态的改变吗?然后你就可以采取最新的这个特定动作。