NgRx Effects等待结果

huangapple go评论69阅读模式
英文:

NgRx Effects waiting for result

问题

我在我的项目中设置了ngrx-effects来获取数据:

在组件中派发 -> effect调用http服务 -> http服务返回数据 -> effect通过action将数据传递给store -> 组件从store的observable获取数据

现在我正在尝试使用类似的方法实现简单的“创建”功能,但我很难看到如何在effects中干净地做到这一点。

据我所知,操作的顺序应该是:

在组件中派发“created”动作 -> reducer将对象添加到store -> effect通过服务发起http请求 -> effect获取http结果 -> effect调用成功/失败动作

问题在于没有办法“等待”http请求的结果。如果http请求失败,我将不得不从store中删除该对象(这会导致糟糕的用户体验)。

是否有一种干净的方式来实现这种类型的功能,并且是否要使用effects呢?还是答案只是直接从组件中调用服务?

英文:

I have set up ngrx-effects in my project for fetching data:

dispatch in component -> effect calls http service -> http service returns data -> effect passes data to store through action -> component gets data from store observable

Now I am trying to implement simple "create" functionality with a similar approach, but I am struggling to see how to do this cleanly using effects.

As far as I can tell the order of operations would be:

dispatch "created" action in component -> reducer adds object to the store -> effect makes http request through service -> effect gets http result -> effect calls success/failure action

The issue is that there is no way to "wait" for the result of the http request. If the http request fails I would have to remove the object from the store again (which makes for a bad user experience).

Is there a clean way this kind of functionality is implemented with effects? Or is the answer just not to use effects for this and call the service directly from the component?

答案1

得分: 1

常见但冗长的方法是将用于保存对象的操作拆分开来。其中一个操作会触发一个不保存 payload 到存储的动作,它只触发效果。效果运行,成功时触发另一个操作来保存数据到存储中。

export const myActions = createActionGroup({
  source: 'Some state',
  events: {
    Add: props<{ myData: MyDataDto }>(), // 这个没有 reducer,或者只用于设置 `isLoading` 标志
    'Add Success': props<{ result: MyDataDto }>(), // 有与之关联的 reducer
    'Add Failure': emptyProps(),
  },
});
// 即使不使用 createActionGroup(...),也可以执行相同的操作
// 只需自己编写操作

上述所有操作还可以更改 isLoading 标志的状态(如果使用的话)。无需将其设置为属性,Add 将其设置为 true,Success 和 Failure 都将其设置为 false
然后,您的效果可以如下所示:

add$ = createEffect(() => this.actions$.pipe(
  ofType(myActions.add),
  switchMap(({ myData }) => /* 发出 HTTP 请求 */),
  map(result => myActions.addSuccess({ result })),
  catchError(/* 处理错误 */)
  );
);

在操作中接收 payload,使用服务将其保存到数据库,并根据结果,要么将其保存到存储中,要么处理错误。

英文:

Common yet verbose way is to split the actions you use to save the object. One of them dispatches an action without saving the paylod to the store, it just triggers the effect. Effect runs and on success it dispatches another action to save the data into the store.

export const myActions = createActionGroup({
  source: &#39;Some state&#39;,
  events: {
    Add: props&lt;{ myData: MyDataDto }&gt;(), // no reducer for this one, or just for setting `isLoading` flag
    &#39;Add Success&#39;: props&lt;{ result: MyDataDto }&gt;(), // has reducer tied to it
    &#39;Add Failure&#39;: emptyProps(),
});
// You can do the same thing even if you&#39;re not using createActionGroup(...)
// Just write the actions on your own

All actions from above can also change the state of your isLoading flag (if using any). No need to set it as a prop, Add sets it to true, both Success and Failure set it to false.
Your effect can then look like this:

add$ = createEffect(() =&gt; this.actions$.pipe(
  ofType(myActions.add),
  switchMap(({myData}) =&gt; /* make the HTTP request */),
  map(result =&gt; myActions.addSuccess({ result })),
  catchError(/* handle error */)
  );
);

Receive the payload in the action, use the service to save it to the DB and depending on the result, you either save it to the store, or handle an error.

huangapple
  • 本文由 发表于 2023年6月26日 01:44:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76551710.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定