redux-observable + socket.io:动作必须是普通对象。使用自定义中间件进行异步操作

时间:2017-07-09 18:59:21

标签: reactjs socket.io redux rxjs redux-observable

我正在使用redux-observable和socket.io并试图通过socket.emits来验证令牌,但是redux-observable说出了关于操作的事情。然后我尝试使用switchMaps,但我只在方法列表中进行了最后一次调度。我尝试了不同的运算符和方法,但它也没有用。我哪里错了?提前谢谢。

这是代码。首先,如果令牌为suc===,我们会在服务器上发出令牌(例如它的suc,就像成功一样),我发送带verifySuccess的发送1}},否则为verifyError。我已经测试了服务器端,以防可能存在问题,但事实并非如此。

export default function verify(action$) {
  return action$.ofType(TOKEN_VERIFY_REQUEST)
    .map(action => Observable.of(socket.emit('verify', { token: 'suc' })))
    .mapTo(
      Observable.fromEvent(socket, 'verifySuccess')
        .mapTo({ type: TOKEN_VERIFY_SUCCESS })
    )
    .mapTo(
      Observable.fromEvent(socket, 'verifyError')
        .mapTo({ type: TOKEN_VERIFY_FAILURE })
    )
}

回到

socket.on('verify', async (data) => {
      console.log(`got verify with`.red)
      console.log(data)
      const msgs = {
        suc: { msg: 'Received data' },
        err: { msg: 'Error in request' }
      }
      console.log(`data.token is ${data.token}`)
      if (data.token === 'suc') {
        console.log(`sending success`)
        socket.emit('verifySuccess', msgs.suc)
      } else {
        console.log(`sending error`)
        socket.emit('verifyError', msgs.err)
      }
     }) 

1 个答案:

答案 0 :(得分:1)

可能存在一些关于RxJS的基本误解,所以我会花一些时间来真正获得它的基础,或者考虑使用像redux-thunk这样的东西,如果你的异步需求并不比这更复杂。

所以这里有一些事情可以指导你:

  • 你的map正在返回一个Observable,这意味着你现在有一个Observable of Observables又称Observable<Observable>,这几乎肯定不是你想要的。
  • 目前还不清楚Observable.of(socket.emit('verify', { token: 'suc' })))是什么意思,因为socket.emit()返回套接字本身,所以你发出然后将动作映射到Socket本身的Observable?
  • mapTo用法也可能不是你想要的。第二个取消第一个,你再次创建一个Observable of Observable。所以你的史诗正在发出(并因此调度)一个Observables流,而不是动作,这就是为什么你从redux那里得到“动作必须是普通对象”的错误。

我犹豫是否给你一个解决方案,但我会要求你试着真正理解它,而不仅仅是复制粘贴。也许退后一步,试着忘记你目前关于Rx如何运作并重新开始的信念?那么你可能会有“啊哈!”时刻:))

我猜你打算做这样的事情:

export default function tokenVerifyRequestEpic(action$) {
  return action$.ofType(TOKEN_VERIFY_REQUEST)
    .do(() => {
      socket.emit('verify', { token: 'suc' }));
    })
    .mergeMap(() =>
      Observable.race(
        Observable.fromEvent(socket, 'verifySuccess')
          .mapTo({ type: TOKEN_VERIFY_SUCCESS }),
        Observable.fromEvent(socket, 'verifyError')
          .mapTo({ type: TOKEN_VERIFY_FAILURE })
      )
    );
}

这是详细的内联评论:

export default function tokenVerifyRequestEpic(action$) {
  // filter out all actions except TOKEN_VERIFY_REQUEST
  return action$.ofType(TOKEN_VERIFY_REQUEST)
    // perform the side effect of emitting the 'verify' message
    .do(() => {
      socket.emit('verify', { token: 'suc' }));
    })
    // One problem with this code is that it might not properly account for
    // multiple concurrent TOKEN_VERIFY_REQUEST requests. e.g. How are those
    // handled by the server? How should be they be handled in the UI?
    // If it's not supposed to be possible, it might be useful to assert
    // against that condition so that if it does accidentally happen you
    // throw an error
    .mergeMap(() =>
      // Race between either a 'verifySuccess' or 'verifyError'
      // This assumes one or the other will always happen, if not
      // then you might want to add a timeout() or similar
      Observable.race(
        Observable.fromEvent(socket, 'verifySuccess')
          .mapTo({ type: TOKEN_VERIFY_SUCCESS }),
        Observable.fromEvent(socket, 'verifyError')
          .mapTo({ type: TOKEN_VERIFY_FAILURE })
      )
    );
}