首页 > 解决方案 > Redux Observable - 如何发送一个动作来开始一个单独的史诗,然后等待史诗响应(或超时)

问题描述

所以我基本上有一个websocket 连接,这允许我通过 WEBSOCKET_MESSAGE_SEND 发送通用消息并通过 WEBSOCKET_MESSAGE_RECEIVED 操作接收它们。

但是,在某些情况下,我想以与 Ajax REST 调用类似的方式发出请求。例如,为用户请求文档列表,我可能想要一个史诗:

  1. 接收一个动作,例如({ type: GET_DOCUMENTS })
  2. 生成一个随机密钥来跟踪当前的请求,我们称之为'request_id'
  3. 发送({ type: WEBSOCKET_MESSAGE_SEND, request_id })动作。
  4. 等待任何一个
    1. 一个动作({ type: WEBSOCKET_MESSAGE_RECEIVED, request_id, message })**必须有一个匹配的“request_id”,否则它应该被忽略。
      • -> 发出一个动作,例如({ type: GET_DOCUMENTS_SUCCESS, documents: message })
    2. 超时,例如 10 秒
      • -> 发出一个动作,例如({ type: GET_DOCUMENTS_TIMEOUT })

我一直在努力将其放入代码中,我认为整个史诗中最尴尬的部分是我想在史诗中间发出一个动作并等待。这对我来说感觉不太对劲……ani-pattern?但我不确定我应该怎么做。

标签: rxjsredux-observable

解决方案


这是正确的。没有什么好的方法可以在史诗的中间发出一个动作。把史诗分成两部分怎么样?

const getDocumentsEpic = action$ =>
    action$.pipe(
        ofType("GET_DOCUMENTS"),
        map(() => {
          const requestId = generateRequestId();
          return {
            type: "WEBSOCKET_MESSAGE_SEND",
            requestId
          };
        })
    );

const websocketMessageEpic = action$ =>
    action$.pipe(
        ofType("WEBSOCKET_MESSAGE_SEND"),
        switchMap(requestId => {
          return action$.pipe(
              ofType("WEBSOCKET_MESSAGE_RECEIVED"),
              filter(action => action.requestId === requestId),
              timeout(10000),
              map(({ message }) => ({
                type: "GET_DOCUMENTS_SUCCESS",
                documents: message
              })),
              catchError(() => of({ type: "GET_DOCUMENTS_TIMEOUT" }))
          );
        })
    );

推荐阅读