英文:
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: 'Some state',
events: {
Add: props<{ myData: MyDataDto }>(), // no reducer for this one, or just for setting `isLoading` flag
'Add Success': props<{ result: MyDataDto }>(), // has reducer tied to it
'Add Failure': emptyProps(),
});
// You can do the same thing even if you'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(() => this.actions$.pipe(
ofType(myActions.add),
switchMap(({myData}) => /* make the HTTP request */),
map(result => 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论