【问题标题】:redux-observable + socket.io: Actions must be plain objects. Use custom middleware for async actionsredux-observable + socket.io:动作必须是普通对象。使用自定义中间件进行异步操作
【发布时间】:2017-07-09 18:59:21
【问题描述】:

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

这是代码。首先,我们在服务器上发出令牌(例如它是suc,就像成功一样),如果令牌是===suc,我用verifySuccess 发送发射,否则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)
      }
     }) 

【问题讨论】:

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


    【解决方案1】:

    对于 RxJS 可能存在一些基本的误解,所以我会花一些时间来真正打下坚实的基础,或者如果你的异步需求不比这更复杂,我会考虑使用类似 redux-thunk 的东西。

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

    • 您的 map 正在返回一个 Observable,这意味着您现在有一个 Observable 的 Observable 也就是 Observable<Observable> 这几乎肯定不是您想要的。
    • 不清楚Observable.of(socket.emit('verify', { token: 'suc' }))) 的用途是什么,因为socket.emit() 返回套接字本身,所以您发出然后将操作映射到套接字本身的一个可观察对象?
    • mapTo 的用法也可能不是您想要的。第二个取消了第一个,你再次创建了一个 Observable 的 Observable。所以你的史诗是发射(并因此调度)一个 Observable 流,而不是动作,这就是为什么你从 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 })
          )
        );
    }
    

    这里是详细的内联 cmets:

    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 })
          )
        );
    }
    

    【讨论】:

    • 谢谢,它按我希望的那样工作。你能举例说明如何添加超时吗?
    猜你喜欢
    • 1970-01-01
    • 2017-09-30
    • 2018-11-12
    • 2018-01-31
    • 2018-03-27
    • 1970-01-01
    • 2018-01-30
    • 2017-05-01
    相关资源
    最近更新 更多