gpt4 book ai didi

redux - 如何使用 redux-observable 做一个简单的通知系统?

转载 作者:行者123 更新时间:2023-12-01 12:21:03 25 4
gpt4 key购买 nike

我正在尝试使用 redux-observable 做一个简单的通知系统。我是新来的 rxjs所以我很难做到。

我想要做的是:

  • 发送意图以显示通知
  • 使用 Epic 检测意图
  • 调度插入新通知的 Action
  • 等待 3 秒
  • 调度另一个删除旧通知的操作

  • 这是我的史诗:
    import { NOTIFICATION_DISPLAY_REQUESTED } from '../actions/actionTypes';
    import { displayNotification, hideNotification } from '../actions/notifications';

    export const requestNotificationEpic = (action$, store) =>
    action$.ofType(NOTIFICATION_DISPLAY_REQUESTED)
    .mapTo(displayNotification(action$.notification))
    .delay(3000)
    .mapTo(hideNotification(action$.notification));

    真正发生的是 NOTIFICATION_DISPLAY_REQUESTED已调度,3 秒后, hideNotification被 dispatch 。 displayNotification永远不会发生。

    我可以 dispatch displayNotification看来,延迟3秒再调度 hideNotification .但是,如果有 3 个以上的事件通知,我想在添加新通知之前删除最后一个通知。这就是为什么我 dispatch displayNotification在这个简单的情况下,从史诗内部手动。

    那么,我如何实现这一目标?对不起,如果这是一个 super 简单的问题,我只是这一切的新手,需要一些帮助。

    注:我知道 redux-saga存在,只是 redux-obsevable对我来说更有意义。

    最佳答案

    如果你是 RxJS 的新手,这不是那么简单 :)

    前面的几件事:

    运营商链

    Epic 是一个函数,它接受一个 Action 流并返回一个 Action 流。 Action 进去, Action 出来。您链接以转换匹配操作的函数称为运算符。链接运算符(operator)很像链接花园软管或电源线——值(value)从一个流向另一个。它也非常类似于只是链接常规函数,如 third(second(first()))除了 Observables 有一个额外的时间维度,所以运算符应用于流经它们的每个值。

    所以如果你说 stream.mapTo(x).mapTo(y)您首先映射到 x 的事实当你 .mapTo(y) 时变得毫无意义自 mapTo忽略源的值,而只是将其映射到提供的值。

    如果您改为使用 map ,它可能会变得更加明显:

    stream.map(value => 'a message').map(message => message + '!!!')

    更明确地说,这种操作符的链接是 RxJS,不是特定于 redux-observable,它更像是一种使用 idiomatic RxJS 的模式。用少量胶水进入redux。
    action$是一个 Observable(技术上是 ActionsObservable)

    参数 action$是一个 Observable 的 Action ,而不是一个实际的 Action 本身。所以 action$.notification将是 undefined .这就是人们通常使用美元符号后缀的原因之一,以表示它是这些东西的流。

    考虑只有 2 个 Action ,而不是 3 个

    您的示例显示您使用三个操作 NOTIFICATION_DISPLAY_REQUESTED和另外两个来显示和隐藏通知。在这种情况下,原始意图 Action 与 displayNotification()基本相同因为它将在另一个之后同步调度。

    考虑只有两个操作,一个用于“显示此通知”,另一个用于“隐藏此通知”。虽然这不是规则,但它通常可以简化您的代码并提高性能,因为您的 reducer 不必运行两次。

    这就是您的情况(当然,您可以随意命名):
    export const displayNotificationEpic = (action$, store) =>
    action$.ofType(DISPLAY_NOTIFICATION)
    .delay(3000)
    .map(action => hideNotification(action.notification));

    // UI code kicks it off some how...
    store.dispatch(displayNotification('hello world'));

    然后你的 reducer 会收到 DISPLAY_NOTIFICATION然后 3 秒后 HIDE_NOTIFICATION (随便订购)。

    此外,重要的是要记住 rom redux-observable docs :

    REMEMBER: Epics run alongside the normal Redux dispatch channel, after the reducers have already received them. When you map an action to another one, you are not preventing the original action from reaching the reducers; that action has already been through them!



    解决方案

    虽然我建议在这种情况下只使用两个操作(见上文),但我确实想直接回答你的问题!由于 RxJS 是一个非常灵活的库,因此有很多方法可以完成您的要求。

    这里有一对:

    一部史诗,使用 concat

    concat operator用于一次订阅所有提供的 Observables,只有当当前一个完成时才移动到下一个。它一次“耗尽”每个 Observable 一个。

    如果我们想创建一个发出一个 Action 的流,等待 3000 毫秒然后发出另一个 Action ,你可以这样做:
    Observable.of(displayNotification(action.notification))
    .concat(
    Observable.of(hideNotification(action.notification))
    .delay(3000)
    )

    或这个:
    Observable.concat(
    Observable.of(displayNotification(action.notification)),
    Observable.of(hideNotification(action.notification))
    .delay(3000)
    )

    在这种情况下,它们具有完全相同的效果。关键是我们正在应用 delay与第一个不同的 Observable —— 因为我们只想延迟第二个 Action 。我们隔离他们。

    要在您的史诗中使用,您需要一个合并策略运算符,例如 mergeMap , switchMap等。这些对于学习非常重要,因为它们在 RxJS 中经常使用。
    export const requestNotificationEpic = (action$, store) =>
    action$.ofType(NOTIFICATION_DISPLAY_REQUESTED)
    .mergeMap(action =>
    Observable.concat(
    Observable.of(displayNotification(action.notification)),
    Observable.of(hideNotification(action.notification))
    .delay(3000)
    )
    );

    两个不同的史诗

    另一种方法是创建两个不同的史诗。一个负责将第一秒映射到第二秒,另一个负责等待 3 秒后隐藏。
    export const requestNotificationEpic = (action$, store) =>
    action$.ofType(NOTIFICATION_DISPLAY_REQUESTED)
    .map(action => displayNotification(action.notification));

    export const displayNotificationEpic = (action$, store) =>
    action$.ofType(DISPLAY_NOTIFICATION)
    .delay(3000)
    .map(action => hideNotification(action.notification));

    这是有效的,因为史诗可以匹配 全部 Action ,甚至是其他史诗发出的 Action !这允许干净的分离、组合和测试。

    这个例子(对我来说)更好地表明,对于这个例子来说,有两个意图 Action 是不必要的,但可能有一些你没有提供的要求来证明它是合理的。

    如果这很令人困惑,我建议先深入研究 RxJS。教程、视频、研讨会等。这只是表面的,它会深入得多,但对于大多数坚持使用它的人来说,返回是巨大的。

    关于redux - 如何使用 redux-observable 做一个简单的通知系统?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43941480/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com