首页 > 解决方案 > 如何独立触发 NGRX Selector foreach 子组件

问题描述

我有一个组件,它在仪表板中充当小部件。因此,我将使用 an*ngFor来呈现与仪表板一样多的小部件。这是唯一的一个,并从父WidgetComponent级接收其数据的一部分。@Input()

父母

<app-widget *ngFor="let widget of widgets"
      [widget]="widget">
</app-widget>

在孩子中,我使用 NGRX 选择器监听一个事件:

this.store.pipe(
   select(fromStore.selectPage, {widgetId: this.widgetId, page: this.paginator.currentPage}),
   distinctUntilChanged() // can be used, but is unnecessary
).subscribe(rows => {
   console.log(rows);
});

当我想更改页面时,我会在我的商店中发送一个新事件:

ngAfterViewInit(): void {
  const pages = currentPage < 3
    ? [1, 2, 3]
    : [currentPage - 1, currentPage, currentPage + 1];

  const request: PaginatedData = {
    widgetId: this.widget.id,
    itemsPerPage: paginator.itemsPerPage,
    pages
  };

  this.store.dispatch(updatePagesAction({request}));
}

选择器:

export const selectPage = createSelector(selectState, (state, props) => {
  const table = state.widgetTables.find(x => x.widgetId === props.widgetId);
  if (typeof table === 'undefined') {
    return [];
  }

  const existingPageKey = Object.keys(table.pages).find(key => key === props.page.toString());
  return existingPageKey ? table.pages[existingPageKey] : [];
});

问题:当我为一个小部件调度一个动作时,将触发所有在商店同时监听的小部件的选择器。

我只需要为原因小部件触发选择器。问题可能是我对所有小部件使用相同的选择器?

我不能filter()在我的小部件组件中使用 a ,pipe()因为即使我使用类似filter(x => x.widgetId === this.widget.Id)的东西,事件也会被触发并且所有小部件都将再次接收数据,即使与最后一个值相等。

啊,我知道:这可能是因为每次更改面板时,我的商店都会返回一个新状态(对于所有小部件),因此选择器会被所有人触发。

另外,我将此功能存储在一个运行良好的服务中,但是由于该应用程序已经在另一个模块中使用了ngrx,我认为最好对齐必须保存在内存中并稍后使用的所有数据,以便保存在 ngrx 商店内(而不是使用自定义服务)。

谢谢

标签: javascriptangulartypescriptselectorngrx

解决方案


我将如何解决这个问题

我认为您可以使用返回选择器的函数,尝试如下实现

export const selectPageWith = ({widgetId, page}: widgetId: number, page: any) => 
  createSelector(selectState, state => {
    const table = state.widgetTables.find(x => x.widgetId === widgetId);
    if (typeof table === 'undefined') {
      return [];
    }
    const existingPageKey = Object.keys(table.pages).find(key => key === page.toString());
     return existingPageKey ? table.pages[existingPageKey] : [];
  })

现在你可以在你的组件中使用它,比如

this.store.pipe(
   select(fromStore.selectPageWith({widgetId: this.widgetId, page: this.paginator.currentPage}),
   distinctUntilChanged() // can be used, but is unnecessary
).subscribe(rows => {
   console.log(rows);
});

解释

简单地说,我们正在尝试为每个小部件创建唯一的选择器。通过创建返回选择器的函数,不同的参数为每个小部件生成不同的选择器


推荐阅读