如何显示成功消息 NgRX Effects 和调度事件
How to display a success message NgRX Effects and dispatch events
减速器:
export const reducer = (state = initialstate, action: any) => {
switch (action.type) {
case ADD_USER: {
return {
...state,
userAdded: false
}
},
case ADD_USER_SUCCESS: {
return {
...state,
user: action.payload
userAdded: true
}
},
case ADD_USER_FAIL: {
return {
...state,
userAdded: false
}
}
}
}
效果:
login$ = createEffect(() =>
this.actions$.pipe(
ofType(UserAction.ADD_USER),
exhaustMap(action =>
this.userService.addUser("USER").pipe(
map(user => UserAction.AddUserSuccess({ "user" })),
catchError(error => of(UserAction.AddUserFail({ error })))
)
)
)
);
component.ts:
onClickAddUser(): void {
this.store.dispatch(new AddUser('USER'));
this.store.pipe(select(getUser), take(1)).subscribe((isUserAdded) => {
if(isUserAdded) {
this.router.navigateByUrl('/success'); // Expectation is to navigate to success page
} else {
this.router.navigateByUrl('/home'); // for first time it's always going to home screen even the success action being dispatched and the value been set to true.
}
});
}
点击该方法,一个动作被分派并跟进一个效果,我的情况是 api 调用成功并且一个成功的动作也被分派(在我的减速器中我设置了一个标志true),在从 click 方法发送 AddUser 操作之后,如果 API return,我订阅标志 (isUserAdded)
以将用户导航到 /success
屏幕成功响应,在我的例子中,当我订阅标志时,它没有在商店中更新,因此用户导航到主屏幕(但期望是导航到成功屏幕,因为 API 是成功的) .是否可以等待商店中的值更新然后订阅它,或者是否有任何最佳实践来处理这种情况??
一旦成功操作被分派,我可以编写一个效果来导航用户,但我的意思是,一旦标志设置为真,我确实有其他功能要处理,因此必须在组件中执行所有操作。
你不能只 return 在你的效果 fn 中像 UserAddedSuccess 和 catchError UserAddedFail 写另一个效果,它将监听 useraddedsuccess 动作并在成功时重定向所需的页面,在第一个效果 catcherror return UserAddedFail 操作和相同的过程?
事件顺序如下:
- 你发送一个
AddUser
动作
this.store.dispatch(new AddUser('USER'));
- Reducer 被调用,状态被改变并且
userAdded
被设置为 false
case ADD_USER: {
return {
...state,
userAdded: false
}
},
- 调用选择器并通知订阅者,但您还没有任何订阅
- 效果
ADD_USER
被调用,异步请求被发送到 userService
login$ = createEffect(() =>
this.actions$.pipe(
ofType(UserAction.ADD_USER),
exhaustMap(action =>
this.userService.addUser("USER").pipe(
map(user => UserAction.AddUserSuccess({ "user" })),
catchError(error => of(UserAction.AddUserFail({ error })))
)
)
)
);
- 您在管道中使用
take(1)
运算符订阅了 getUser
选择器
this.store.pipe(select(getUser), take(1)).subscribe((isUserAdded) => {
if(isUserAdded) {
this.router.navigateByUrl('/success');
} else {
this.router.navigateByUrl('/home');
}
});
- 选择器 returns 来自商店的
userAdded
标志的值为 false
,您的回调函数被调用,订阅被 take(1)
操作员取消
- 路由器导航到“/home”
- 来自
userService
的回复被返回并且 userAdded
标志设置为 true
但您的订阅已经取消
如果您想要 component.ts
中的简单解决方案,只需尝试订阅 take(2), skip(1)
:
this.store.pipe(select(getUser), take(2), skip(1)).subscribe((isUserAdded) => {
if(isUserAdded) {
this.router.navigateByUrl('/success');
} else {
this.router.navigateByUrl('/home');
}
});
我想你可以 dispatch 多个动作,你必须创建单独的 action 来处理 routing.
login$ = createEffect(() =>
this.actions$.pipe(
ofType(UserAction.ADD_USER),
exhaustMap(action =>
this.userService.addUser("USER").pipe(
switchMap(user => [
UserAction.AddUserSuccess({ "user" }),
routeAction.routeto('success')
])
,catchError(error => [
UserAction.AddUserFail({ error }),
routeAction.routeto('Home');
])
)
)
)
);
减速器:
export const reducer = (state = initialstate, action: any) => {
switch (action.type) {
case ADD_USER: {
return {
...state,
userAdded: false
}
},
case ADD_USER_SUCCESS: {
return {
...state,
user: action.payload
userAdded: true
}
},
case ADD_USER_FAIL: {
return {
...state,
userAdded: false
}
}
}
}
效果:
login$ = createEffect(() =>
this.actions$.pipe(
ofType(UserAction.ADD_USER),
exhaustMap(action =>
this.userService.addUser("USER").pipe(
map(user => UserAction.AddUserSuccess({ "user" })),
catchError(error => of(UserAction.AddUserFail({ error })))
)
)
)
);
component.ts:
onClickAddUser(): void {
this.store.dispatch(new AddUser('USER'));
this.store.pipe(select(getUser), take(1)).subscribe((isUserAdded) => {
if(isUserAdded) {
this.router.navigateByUrl('/success'); // Expectation is to navigate to success page
} else {
this.router.navigateByUrl('/home'); // for first time it's always going to home screen even the success action being dispatched and the value been set to true.
}
});
}
点击该方法,一个动作被分派并跟进一个效果,我的情况是 api 调用成功并且一个成功的动作也被分派(在我的减速器中我设置了一个标志true),在从 click 方法发送 AddUser 操作之后,如果 API return,我订阅标志 (isUserAdded)
以将用户导航到 /success
屏幕成功响应,在我的例子中,当我订阅标志时,它没有在商店中更新,因此用户导航到主屏幕(但期望是导航到成功屏幕,因为 API 是成功的) .是否可以等待商店中的值更新然后订阅它,或者是否有任何最佳实践来处理这种情况??
一旦成功操作被分派,我可以编写一个效果来导航用户,但我的意思是,一旦标志设置为真,我确实有其他功能要处理,因此必须在组件中执行所有操作。
你不能只 return 在你的效果 fn 中像 UserAddedSuccess 和 catchError UserAddedFail 写另一个效果,它将监听 useraddedsuccess 动作并在成功时重定向所需的页面,在第一个效果 catcherror return UserAddedFail 操作和相同的过程?
事件顺序如下:
- 你发送一个
AddUser
动作
this.store.dispatch(new AddUser('USER'));
- Reducer 被调用,状态被改变并且
userAdded
被设置为false
case ADD_USER: {
return {
...state,
userAdded: false
}
},
- 调用选择器并通知订阅者,但您还没有任何订阅
- 效果
ADD_USER
被调用,异步请求被发送到userService
login$ = createEffect(() =>
this.actions$.pipe(
ofType(UserAction.ADD_USER),
exhaustMap(action =>
this.userService.addUser("USER").pipe(
map(user => UserAction.AddUserSuccess({ "user" })),
catchError(error => of(UserAction.AddUserFail({ error })))
)
)
)
);
- 您在管道中使用
take(1)
运算符订阅了getUser
选择器
this.store.pipe(select(getUser), take(1)).subscribe((isUserAdded) => {
if(isUserAdded) {
this.router.navigateByUrl('/success');
} else {
this.router.navigateByUrl('/home');
}
});
- 选择器 returns 来自商店的
userAdded
标志的值为false
,您的回调函数被调用,订阅被take(1)
操作员取消 - 路由器导航到“/home”
- 来自
userService
的回复被返回并且userAdded
标志设置为true
但您的订阅已经取消
如果您想要 component.ts
中的简单解决方案,只需尝试订阅 take(2), skip(1)
:
this.store.pipe(select(getUser), take(2), skip(1)).subscribe((isUserAdded) => {
if(isUserAdded) {
this.router.navigateByUrl('/success');
} else {
this.router.navigateByUrl('/home');
}
});
我想你可以 dispatch 多个动作,你必须创建单独的 action 来处理 routing.
login$ = createEffect(() =>
this.actions$.pipe(
ofType(UserAction.ADD_USER),
exhaustMap(action =>
this.userService.addUser("USER").pipe(
switchMap(user => [
UserAction.AddUserSuccess({ "user" }),
routeAction.routeto('success')
])
,catchError(error => [
UserAction.AddUserFail({ error }),
routeAction.routeto('Home');
])
)
)
)
);