使用惯用的redux可观察到的队列和取消事件



给定下载管理器的示例。可以有许多主动下载。

可以派遣操作以开始,停止,标记完成并标记任何特定下载的下载进度。

const START_DOWNLOAD = "START_DOWNLOAD";
const startDownload = payload => ({ type: START_DOWNLOAD, payload });
const DOWNLOAD_PROGRESS = "DOWNLOAD_PROGRESS";
const downloadProgress = payload => ({ type: DOWNLOAD_PROGRESS, payload });
const STOP_DOWNLOAD = "STOP_DOWNLOAD";
const stopDownload = payload => ({ type: STOP_DOWNLOAD, payload });
const COMPLETE_DOWNLOAD = "COMPLETE_DOWNLOAD";
const completeDownload = payload => ({ type: COMPLETE_DOWNLOAD payload });

这些操作将包含一个ID来识别下载,并可以使用以下还原器修改REDUX状态:

const downloadReducer = (state = initialState, action) => {
  switch (action.type) {
    case STOP_DOWNLOAD:
      return {
        ...state,
        [action.payload.id]: {
          state: "IDLE",
        },
      };
    case START_DOWNLOAD:
      return {
        ...state,
        [action.payload.id]: {
          state: "IN_PROGRESS",
          progress: 0,
        },
      };
    case DOWNLOAD_PROGRESS:
      return {
        ...state,
        [action.payload.id]: {
          state: "IN_PROGRESS",
          progress: action.payload.progress,
        },
      };
    case COMPLETE_DOWNLOAD:
      return {
        ...state,
        [action.payload.id]: {
          state: "DONE",
          progress: 100,
        },
      };
    default:
      return state;
  }
};

现在出现了有关如何使用Redux可观察到的异步调度这些动作的问题。

例如,我们可以做这样的事情:

const downloadEpic = action$ =>
  action$.ofType(START_DOWNLOAD).mergeMap(action =>
    downloader
    .takeUntil(
      action$.filter(
        stop =>
        stop.type === STOP_DOWNLOAD &&
        stop.payload.id === action.payload.id,
      ),
    )
    .map(progress => {
      if (progress === 100) {
        return completeDownload({
          id: action.payload.id
        });
      } else {
        return downloadProgress({
          id: action.payload.id,
          progress
        });
      }
    }),
  );

这有效。但是,如果我们想限制允许的活动下载次数。我们可以用concatMap替换mergeMap,以一次只允许一个活动下载。或者我们可以将并发参数提供给mergeMap,并准确指定我们要一次可观察的内下载器的执行。

但是,这带来了我们现在无法停止排队下载的问题。

我创建了一个完整的工作示例,您可以在这里尝试。

如何使用RXJS和REDUX限制和队列下载,并以最惯用的方式观察?

我已经关注了几天,但是没有时间用完整的代码给您一个可靠的答案,因为它相对涉及。因此,相反,我会给您TL; DR版本总比没有我希望的好:)


我的直觉告诉我,我将有一个UI调度一个代表尝试下载而不是真正保证的动作。例如ATTEMPT_DOWNLOAD。史诗般的人会听取此操作,并检查当前的活动下载次数是否超过> =最大值,如果是的,则会发出一项动作以加入下载而不是启动下载。

您的还原器将存储那些活跃的人的下载ID,并下载了排队的ID。例如

{ active: ['123', '456', ...etc], queued: ['789'] }

您既要专门跟踪主动/排队,又要知道它们的计数active.lengthqueued.length

当下载完成史诗般的地方时,某处会检查是否有排队的下载,如果是的,则Dequeue One。您的工作方式正是个人喜好。例如如果史诗发射DEQUEUE_DOWNLOAD或其他。

如果派遣取消操作,您的还原器将需要查看activequeued,并在其中删除ID。如果实际上是活跃的,而不仅仅是排队,那么处理下载的史诗将是在聆听取消动作,它将阻止它并进行与上述相同的Dequeue检查。


这有点手动,但要点很大:

  • 您的UI组件不应该在尝试之前如何或何时排队,尽管它可以通过查看Redux状态(例如显示"下载queued"或erthing)来看到事实之后
  • 小心不要在多个位置重复下载的状态。例如如果它活跃,您的商店中只有一个真实的来源,说它是
  • 史诗在还原器之后运行,将其用于您的优势。
  • 可能会有一个史诗般的工作是唯一的工作是聆听 true 下载请求并执行该请求,而不了解排队或类似的东西。然后,该史诗将被其他多个史诗重复使用。通过将其直接称为函数,或者通过像您的真实START_DOWNLOAD
  • 这样的动作发出

并不总是清楚业务逻辑应该在哪里。例如还原器是否应该仅仅是Getter/Setter,还是应该具有更有意义的逻辑并做出决定?在这些情况下,没有很多规则。只是尝试保持一致。

顺便说一句,这完全来自我的肠道。我可能已经发现(或者您仍然发现)实际上这不是一个好的解决方案。只是给我最初的想法!

相关内容

  • 没有找到相关文章