ngrx 组件存储有角度,可以通过效果值进行观察?

问题描述 投票:0回答:1

我尝试在我的 Angular 16 项目中创建一个自定义自动完成组件。 该组件应该能够从我的组件存储中延迟获取数据。

我做到了做这样的事情:

 // MySearchComponent
  @Input({ required: true }) searchValues$?: Observable<SearchInputObject[]>;

  @Input({ required: true }) searchValuesSubscription!: any;// the trigger

  @Input({ required: true }) fieldCtrl!: FormControl<SearchInputObject | null>; // form control to return the selected value

searchValuesSubscription
触发我的效果,以及
searchValues$
商店中关联的选择。

我发现该解决方案对开发人员不太友好,就好像我使用该组件 10 次一样,我必须在父组件中创建这 2 个属性才能使用 MySearchComponent

ngOnInit() {
  this.searchValues$ = this._myStore.companyCategories$;
  this.searchValuesSubscription$ = this._myStore.loadCompanyCategories;
}

并调用组件:

<app-async-search-input
  [fieldCtrl]="docCategoryCtrl"
  [searchValues$]="searchValues$"            
  [searchValuesSubscription]="searchValuesSubscription$">
</app-async-search-input>

效果摘录,以防万一有帮助:)

 readonly loadCompanyCategories = this.effect<void>(trigger$ =>
    trigger$.pipe(
      exhaustMap(() =>
        combineLatest([this.userInstance$, this.selectedCompanyId$]).pipe(
          switchMap(([instance, selectedCompanyId]) => {
            if (instance && selectedCompanyId) {
              return this._apiService.getCompanyCategories(instance, selectedCompanyId).pipe(
                tapResponse(
                  companiesCategories => {
                    this.patchState({
                      nonPersistent: {
                        ...this.get().nonPersistent,
                        companyCategories: companiesCategories,
                      },
                    });
                  },
                  (error: HttpErrorResponse) => console.error(error)
                )
              );
            }
            return [];
          })
        )
      )
    )
  );

这里是一个 stackblitz,显示了我所做的简化版本:https://stackblitz.com/edit/stackblitz-starters-frdx5b?file=src%2Fapp%2Fasync-autocomplete%2Fasync-autocomplete.component.ts 您需要单击“加载书籍”,以便 AsyncAutocompleteComponent 触发商店,然后在选择中显示书籍列表。

有没有办法让触发器返回可观察的值?或者这是不应该用 Effect 完成的事情?还有另一种方法可以做到这一点吗? 我愿意接受所有建议! 谢谢!

ngrx ngrx-component-store component-store
1个回答
0
投票

好的,这是一个分叉的 stackblitz,它显示了处理事件和数据流的正确方法。

正如我在评论中提到的,将可观察量和订阅传递到组件中是一种反模式。除非绝对必要,否则应避免这样做。

我将只发布与上面显示的不同的代码片段......

当您需要在父组件中触发某些内容时,请使用

@Output
,而不是传递订阅。

  @Input({ required: true }) searchValues: Book[] | null = [];

  @Input({ required: true }) fieldCtrl!: FormControl<any | null>; // form control to return the selected value

  @Output() loadBooks = new EventEmitter();

然后该组件应该处理数据的异步绑定,以便每当数据更改时都会为异步自动完成组件运行更改检测。此外,还有一个新的事件处理程序,用于按下按钮时调用存储中的加载。

<p>Select a book :</p>
<app-async-autocomplete
  [searchValues]="searchValues$ | async"
  (loadBooks)="onLoadBooks()"
  [fieldCtrl]="fieldCtrl"
></app-async-autocomplete>

你写的load函数效果也需要一些调整。确实没有必要先使用

exhaustMap
,然后再使用
switchMap
。当您需要在处理效果时展开可观察对象时,我建议使用
combineLastestWith
中的
rxjs
concatLatestFrom 库中找到的 
@ngrx/operators

  readonly loadBooks = this.effect<void>((trigger$) =>
    trigger$.pipe(
      tap((_) => console.log('fetch books')),
      combineLatestWith(this.userInstance$, this.selectedCompanyId$),
      switchMap(([_, instance, selectedCompanyId]) => {
        if (instance && selectedCompanyId) {
          return this._booksHttpService.getBooks().pipe(
            tapResponse(
              (newBooks) => {
                console.log('newBooks=');
                console.table(newBooks);
                this.patchState({
                  books: newBooks,
                });
              },
              (error: HttpErrorResponse) => console.error(error)
            )
          );
        }
        return [];
      })
    )
  );

请参阅 stackblitz 以了解它们如何协同工作。

© www.soinside.com 2019 - 2024. All rights reserved.