redux-saga 进阶概念 Using Channels

时间:2022-01-02 09:39:09

Using Channels(使用通道)

我们已经了解take和put这两个Effects(效果)去和Redux Store进行通讯,Channels(通道)可以使用这些Effects与外部事件资源或者sagas之间进行通讯,Channels(通道)还可以接收store发送的action,实现action队列。

在这一章节,我们将了解:
  • 如何使用 yield actionChannel 这个Effect去缓冲Store发送的特定action。
  • 如何使用eventChannel工厂函数使take这种Effects去链接外部事件源。
  • 如何使用channel工厂函数创建一个通道,并且在take/put的Effects中使用,进行两个Sagas之间的通讯。

Using the actionChannel Effect(使用actionChannel效果)

我们来回顾一个教程例子:
import { take, fork, ... } from 'redux-saga/effects'

function* watchRequests() {
  while (true) {
    const {payload} = yield take('REQUEST')
    yield fork(handleRequest, payload)
  }
}

function* handleRequest(payload) { ... }
以上示例中展示了warch-and-fork模式,watchRequests这个saga使用了fork避免阻塞,是为避免漏掉从store中发送过来的action,每当发生一个名为REQUEST的action,handleRequest这个任务都会被创建,如果在短时间激活了很多action,那将会出现很多handleRequest任务并行执行。

可以想象如果我们有这样的需求:我希望按顺序处理REQUEST这个任务,如果我们同时激活了四个action,我们希望一个一个的执行action任务,第一个REQUEST执行完,再执行第二个action(REQUEST),直到都执行完。

所以我们想把暂未执行的action都放进队列,直到我们处理完当前action,再从队列中取出下一个要执行的action。

Redux-Saga提供一点封装actionChannel效果(Effects),它可以提供这样的队列,我们重写一下刚才的示例:

import { take, actionChannel, call, ... } from 'redux-saga/effects'

function* watchRequests() {
  // 1- Create a channel for request actions
  const requestChan = yield actionChannel('REQUEST')
  while (true) {
    // 2- take from the channel
    const {payload} = yield take(requestChan)
    // 3- Note that we're using a blocking call
    yield call(handleRequest, payload)
  }
}

function* handleRequest(payload) { ... }
第一件事情就是创建action通道,我们使用yield actionChannel(pattern),pattern的内容与先前take(pattern)中的内容一致,不同的是,在执行api的阻塞期间里,actionChannel可以缓冲源源不断的相同消息(action)。

下一步yield take(requestChan),take (parttern)除了上述这种从store获取action内容的使用方法,他还可以用来从channel中获取action内容,take将会阻塞saga直到channel收到一个可用的消息。

最重要的一点,我们使用了一个阻塞的call,saga将会一直阻塞,直到call(handleRequest)返回,如果在阻塞期间又有一个REQUEST(action)被dispatches过来了,他将会被requestChan送到缓冲队列中。

默认情况,actionChannel缓冲队列长度是没有限制的,如果你想对缓冲队列有更多控制的话,你可以使用一个带参数的effect creator,Redux-Saga提供了一些常用队列(none,dropping,sliding)但是你仍然可以实现一个自定义队列,详情参阅Redux-Saga API文档。

举个例子,如果你想处理最近的五个action,你可以这样使用:

import { buffers } from 'redux-saga'
import { actionChannel } from 'redux-saga/effects'

function* watchRequests() {
  const requestChan = yield actionChannel('REQUEST', buffers.sliding(5))
  ...
}

Using the eventChannel factory to connect to external events(使用eventCHannel工厂去链接外部事件)

未完待续,今天先翻译到这,明天继续....