由adapter.updateOne

问题描述

嗨,我试图理解为什么它会给我带来无限循环

我尝试过查找互联网,但是没有什么适合我的需求

这是我的作用

    /**
     * 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))
    })
   )
  }