问题描述
嗨,我试图理解为什么它会给我带来无限循环
我尝试过查找互联网,但是没有什么适合我的需求
这是我的作用
/**
* EFFECT TO GET ALL USRS FROM THE KEYCLOAK SERVER
*/
loadUsers$ = createEffect(() => this.action$.pipe(
ofType(LOAD_USERS),switchMap(() => {
return this.userService.fetchAll().pipe(
map((data: T[]) => LOAD_USERS_SUCCESS({ list: data }))
)
}),catchError((err) => {
return of(LOAD_USERS_Failed({ error: err }))
})
))
/**
* FETCH GROUP PER USER
*/
loadUserGroup$ = createEffect(() => this.action$.pipe(
ofType(LOAD_USER_GROUP),switchMap((action) => {
return this.userService.fetchGroupUser(action.id).pipe(
map((data: any[]) => LOAD_USER_GROUP_SUCCESS({ id: action.id,list: data }))
)
}),catchError((err) => {
return of(LOAD_USER_GROUP_Failed({ error: err }))
})
))
这就是我的调度方式
sub-component.ts
ngOnInit(): void {
console.log(`user id ${this.userId}`)
this.store$.dispatch(LOAD_USER_GROUP({ id: this.userId }))
}
parent.ts
users$: Observable<User[]> = this.store$.select(selectAll)
isLoading$: Observable<boolean> = this.store$.select(isLoading)
isLoadingOther$: Observable<boolean> = this.store$.select(isLoadingOther)
constructor(private store$: Store<any>) {
this.store$.dispatch(LOAD_USERS())
}
减速器
export const userReducer = createReducer(
initialState,/**
* ==============================================
* LOADING REDUCERS
* ==============================================
*/
on(LOAD_USERS_SUCCESS,(state,{ list }) => {
return adapter.addAll(list,{
...state,selectedUserId: undefined,isLoading: false,})
}),on(LOAD_USERS_Failed,err) => {
return {
...state,error: err,}
}),on(LOAD_USERS,(state) => {
return {
...state,error: undefined,isLoading: true
}
}),/**
* ==============================================
* END OF LOADING REDUCERS
* ==============================================
*/
on(LOAD_USER_GROUP,isOtherLoading: true
}
}),on(LOAD_USER_GROUP_SUCCESS,{ id,list }) => {
return adapter.updateOne({
id: id,changes: { ...state.entities[id],group: list }
},{ ...state,isOtherLoading: false,error: undefined })
}),)
我确保效果不会调用自身导致无限循环。或调用另一个最终会自行调用的操作。
但仍然给了我无限循环。
更新 我观察到如果我在减速器中删除了这部分,它不会给我无限循环的结果,但我需要它来更新我选择的实体。
on(LOAD_USER_GROUP_SUCCESS,
已更新 我更新了下面检索用户的方式。只需1个组件
ngOnInit(): void {
this.sub.add(
this.store$.select(routerInfo).pipe(
concatMap(routerValue => {
const id = routerValue.params['id'];
return this.store$.select(selectUserById(id)).pipe(
tap(() => this.store$.dispatch(LOAD_USER_GROUP({ id: id }))),map((user: User) => {
console.log(JSON.stringify(user))
})
)
})
).subscribe(() => {
this.isLoading$ = this.store$.select(isLoading)
})
)
}
解决方法
Reducer从不调度动作。所以... addOne不会触发任何操作。
您的问题是您正在从商店获取ID。使用this.store$.select(selectUserById(id))
并在该可观察范围内,您使用tap(() => this.store$.dispatch(LOAD_USER_GROUP({ id: id }))),
调度LOAD_USER_GROUP,然后您的Effect正在侦听,并且该效果将调度LOAD_USER_GROUP_SUCCESS和您的reducer用
on(LOAD_USER_GROUP_SUCCESS,(state,{ id,list }) => {
return adapter.updateOne({
id: id,changes: { ...state.entities[id],group: list }
},{ ...state,isLoading: false,isOtherLoading: false,error: undefined })
}),
对您的商店进行了更改,并为此“ this.store$.select(selectUserById(id))
发出了新的值,并再次使用tap(() => this.store$.dispatch(LOAD_USER_GROUP({ id: id })))
分派了LOAD_USER_GROUP_SUCCESS并存在您的循环。
您可以避免使用该循环替换此内容:
return this.store$.select(selectUserById(id)).pipe(
tap(() => this.store$.dispatch(LOAD_USER_GROUP({ id: id }))),
与此:
return this.store$.select(selectUserById(id)).pipe(
first(),// import this from "rxjs/operators" I'm not sure about the route but i think that is it
tap(() => this.store$.dispatch(LOAD_USER_GROUP({ id: id }))),
不确定这种糖蜜是否对您的“宏观逻辑”有所帮助,但是使用“ first”运算符时,您只需采用可观察对象发出的第一个值,就可以避免循环。
,我能够找到解决方案。但是,当我单击后退按钮时,似乎正在调用oninit中的代码。我检查了devtools并添加了一个日志,是的,当单击后退按钮时,它正在调用oninit
constructor(private store$: Store<any>,private router: Router) {
this.store$.dispatch(LOAD_USERS())
}
ngOnDestroy(): void {
this.sub.unsubscribe()
}
ngOnInit(): void {
this.sub.add(
this.store$.select(routerInfo).pipe(
map(val => val.params['id'])
).subscribe(id => {
console.log('callin user')
this.store$.dispatch(LOAD_USER_GROUP({ id: id }))
console.log(`id ${id}`)
this.user$ = this.store$.select(selectUserById(id))
})
)
}