【问题标题】:How to dispatch multiple ngrx actions at the same time如何同时调度多个 ngrx 动作
【发布时间】:2020-01-25 04:07:24
【问题描述】:

我正在使用 ngrx 并且有一个场景,我需要同时调度 2 个动作。我的状态具有更新和更新的属性,如下所示。

//from reducer
const defaultCardState: CardState = {
    ids: [],
    entities: {},
    loaded: false,
    loading: false,
    adding: false,
    added: false,
    updating: false,
    updated: false,
    deleting: false,
    deleted: false
};

这些是我从组件中调度的操作

this.store.dispatch(fromCard.updateCard({id: id1, changes: {name: name1}}))
this.store.dispatch(fromCard.updateCard({id: id2, changes: {name: name2}}))

下面是我的动作、reducer和效果

//Update Card Actions
export const updateCard = createAction('[Cards] Update Card', props<{id: string, changes: any}>())
export const updateCardSuccess = createAction('[Cards] Update Card Success', props<{changes: any}>());
export const updateCardFail = createAction('[Cards] Update Card Fail')

//Reducer
on(fromCards.updateCard, (state) => ({...state, updating: true, updated: false})),
    on(fromCards.updateCardSuccess, (state, action: any) => ({...cardAdapter.updateOne(action.changes, state), updated: true, updating: false})),
    on(fromCards.updateCardFail, (state, action: any) => fromCards.updateCardFail),

//Update Card Effect
updateCard$: Observable<Action> = createEffect(() => this.actions$.pipe(
    ofType(fromCardActions.updateCard),
    map((action: any) => { return {id: action.id, changes: action.changes}}),
    switchMap((action: any) => this.cardService.updateCard(action).pipe(
        map((res) => (fromCardActions.updateCardSuccess({changes: action }))),
        catchError(() => of(fromCardActions.updateCardFail))
    ))
))

依次调度这些操作以使更新和更新字段不冲突的最佳方式是什么?如果我只运行其中一个,它可以工作,但如果我像上图所示将它们一起发送,则只有一个完成。我看到两个动作都被分派了,但只有一个成功动作被分派。

【问题讨论】:

    标签: angular typescript redux rxjs ngrx


    【解决方案1】:

    你没有,你有一个不同的动作,有效载荷采用一组卡片而不是一张卡片,然后减速器返回使用多张卡片更新的新状态。您的 api 还应该能够接受一个数组,以便您的效果可以发送多个到服务器。

    【讨论】:

    • 谢谢!所以我会创建一个接受数组的服务,并对后端进行 n 次调用以进行更改?
    • 让您的 api 接受数组的目的是,您可以在一次调用中批量更新,而不是往返服务器。
    【解决方案2】:

    您可以在效果中分派多个操作,我建议您仅在效果中执行此操作

    考虑下面的例子

    @Effect()
    dispatchMultiAction$: Observable<Action> = this.actions$.pipe(
        ofType<SomeAction.Dispatch>(someActions.Dispatch),
        switchMap(_ =>
            of(
                new someActions.InitData(),
                new someActions.GetData(),
                new someActions.LoadData()
            )
        )
    );
    

    【讨论】:

    • 使用mergeMap 这样做更简洁。
    【解决方案3】:

    从技术上讲,使用动作来调度另一个多个动作是非常糟糕的做法。它增加了应用程序的复杂性。一段时间后,您无法调试和理解为什么会分派动作。这段视频 Mike Ryan 用 NgRx 描述了良好的行动卫生: https://youtu.be/JmnsEvoy-gY?t=285

    【讨论】:

    • 链接到 YouTube 视频不是一个可接受的答案。评论很好,但这不是答案。至少解释一下视频中的内容,然后链接到视频作为参考。
    • @AdrianBrand 谢谢你的建议。我改变了答案。我分享了这个链接,因为我认为这是了解 ngrx 中动作架构的非常重要的视频。
    • 谢谢!这段视频实际上非常令人大开眼界。我一直在重用动作,并从中看到了一些陷阱。所以他提到独特的事件动作会创建更多动作,但它们也会创建同样多的效果和减速器,对吗?
    【解决方案4】:

    与托尼的回答类似,但使用了正确的运算符:

    @Effect()
    dispatchMultiAction$: Observable<Action> = this.actions$.pipe(
        ofType<SomeAction.Dispatch>(someActions.Dispatch),
        mergeMap(_ => [
                new someActions.InitData(),
                new someActions.GetData(),
                new someActions.LoadData()
            ])
        )
    );
    

    【讨论】:

    • 您没有使用“of”运算符是否有原因。我不明白为什么它有时用于调度操作,有时不用于。
    • 你可以考虑阅读 learnrxjs。他们对每个运营商都有很好的描述。
    • 谢谢。我想我理解 of 运算符的作用,但我不确定为什么有时动作会像 Tony 上面展示的那样作为 observable 发送,而有时不像你的示例中那样
    • Tony 使用 of([]) 的唯一原因是因为 switchMap 只会返回一个 observable。从本质上讲,他所做的是一种返回多个操作的解决方法。但是,使用mergeMap 我们可以正确返回多个操作。
    【解决方案5】:

    类似于 xandermonkey 的答案,但使用正确的运算符:

    @Effect()
    dispatchMultiAction$: Observable<Action> = this.actions$.pipe(
        ofType<SomeAction.Dispatch>(someActions.Dispatch),
        concatMap(_ => [
                new someActions.InitData(),
                new someActions.GetData(),
                new someActions.LoadData()
            ])
        )
    );
    

    注意 concatMap 和 mergeMap 的区别。因为 concatMap 在前一个完成之前不会订阅下一个 observable,所以延迟 2000ms 的来自源的值将首先发出。与立即订阅内部 observable 的 mergeMap 相比,延迟较小(1000 毫秒)的 observable 将发出,然后是需要 2000 毫秒才能完成的 observable。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-10
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      相关资源
      最近更新 更多