如何通过 id 从 ngrx 商店创建 select 或 select 项目

How to create selector to select an item by id from ngrx store

我阅读了 ngrx 商店的 documentation 关于 selectors 的内容,需要弄清楚如何创建 selector 以便 select 按项目 ID 生成一个项目。当我从 selectAllItems select 或 selectAllItems 获取所有项目时,我已经可以将此作为商店订阅的一部分,但我需要弄清楚如何 select 列表中的特定项目商店里的物品。我的主要原因是 createSelector 提供了我喜欢从中受益的性能提升。

这是我的代码:

import { AppState, Item } from '../../shared/models/index';
import { createSelector } from '@ngrx/store';

export const selectItems = (state: AppState) => state.eventsState;

export const selectAllItems = createSelector(selectItems, (allItems: { items: Item[] }) => {
  if (allItems && allItems.items) {
   return allItems.items.filter((item: Item) => (!item.active && !item.closed));
  } else {
    return allItems.items;
  }
});

然后在我的控制器中,我按 id 过滤以获取所需的项目:

this.store.select(selectors.selectAllItems)
  .filter(data => data !== null)
  .subscribe(allItems => {
    this.item = allItems.filter(item => {
      return item.id === this.navParams.data.id;
    });
  });

我希望能够为该特定项目创建 selector 并像这样使用它:

this.store.select(selectors.selectItemById(this.navParams.data.id))
  .filter(data => data !== null)
  .subscribe(selectedItem => {
    this.item = selectedItem;
  });

我们将不胜感激。

经过一番研究,我解决了自己的问题。我使用工厂函数来获得所需的 selectItemById 选择器。这是我的新选择器:

import { AppState, Item } from '../../shared/models/index';
import { createSelector } from '@ngrx/store';

export const selectItems = (state: AppState) => state.eventsState.items;

export const getItemById = (id) => createSelector(selectItems, (allItems) => {
  if (allItems) {
    return allItems.find(item => {
      return item.itemId === id;
    });
  } else {
    return {};
  }
});

然后我在我的控制器中所要做的就是调用这个选择器并向它传递一个所需商品的 ID 以将商品从商店中取出:

import * as selectors from '../../app/store/selectors';

this.store.select(selectors.getItemById(id))
  .subscribe((item) => {
    this.item = item;
  });

使用实体时,一切都变得容易多了。 当您将它们存储为对象时,其中键是项目的 id,值是项目本身。有两种方法可以将项目保存为数组 - 仅存储 ID 或项目的完整对象。

在减速器中:

export interface ItemsState {
  loaded: boolean;
  loading: boolean;
  items: { [key: string]: Item };
  itemIds: any[];
}

const initialState: ItemsState = {
  loaded: true,
  loading: false,
  items: {
    0: {
      foo: 'bar'
    },
    1: {
      bar: 'foo'
    }
  },
  itemIds: [0, 1]
}

在选择器中:

export const getItems = (state: ItemsState) => state.items;

export const getItemById = (id) => createSelector(
  getItems, 
  (items) => items[id]
);

在容器中(组件):

constructor(
  private store: Store,
  private route: ActivatedRoute
) {}

getItemOnInit(): void {
  // or any other way to retrieve id from route
  const id = this.route.snapshot.params.id;
  this.store.pipe(select(getItemById(id)));
}

根据商店中可用的数据:

export const selectUser = (state: AppState) => state.selectedUser;
export const selectAllBooks = (state: AppState) => state.allBooks;

export const selectVisibleBooks = createSelector(
  selectUser,
  selectAllBooks,
  (selectedUser: User, allBooks: Books[]) => {
    if (selectedUser && allBooks) {
      return allBooks.filter((book: Book) => book.userId === selectedUser.id);
    } else {
          return allBooks;
    }
   }
);

商店中没有的数据:

要 select 一个基于商店中不可用数据的状态,您可以将 props 传递给 selector 函数。这些道具通过每个 selector 和 projector 函数传递。为此,我们必须在组件内部使用 selector 时指定这些道具。

例如,如果我们有一个计数器,我们想乘以它的值,我们可以添加乘法因子作为道具:

selector 或 projector 的最后一个参数是 props 参数,对于我们的示例,它如下所示:

export const getCount = createSelector(
  getCounterValue,
  (counter, props) => counter * props.multiply
);

在组件内部我们可以定义道具:

ngOnInit() {
  this.counter = this.store.pipe(select(fromRoot.getCount, { multiply: 2 }))
}

她的是 Documentation