typescript 如何创建选择器以从 ngrx 商店中按 id 选择项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47520471/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create selector to select an item by id from ngrx store
提问by Oleksiy Kononenko
I read ngrx store's documentationabout selectors and need to figure out how to create a selector in order to select one item by item id. I already can do this as part of store subscription when I get all of the items from selectAllItems
selector, but I need to figure out how to select specific item out of a list of items in the store. My main reason is that createSelector
offers performance gains that I like to benefit from.
我阅读了 ngrx 商店关于选择器的文档,需要弄清楚如何创建选择器以便按项目 ID 选择一个项目。当我从selectAllItems
选择器中获取所有项目时,我已经可以将其作为商店订阅的一部分来执行,但我需要弄清楚如何从商店中的项目列表中选择特定项目。我的主要原因是createSelector
提供了我喜欢从中受益的性能提升。
Here is my code:
这是我的代码:
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;
}
});
Then in my controller i filter by id to get needed item:
然后在我的控制器中,我按 id 过滤以获取所需的项目:
this.store.select(selectors.selectAllItems)
.filter(data => data !== null)
.subscribe(allItems => {
this.item = allItems.filter(item => {
return item.id === this.navParams.data.id;
});
});
I would like to be able to create a selector for that specific item and use it like so:
我希望能够为该特定项目创建一个选择器并像这样使用它:
this.store.select(selectors.selectItemById(this.navParams.data.id))
.filter(data => data !== null)
.subscribe(selectedItem => {
this.item = selectedItem;
});
Any help will be appreciated.
任何帮助将不胜感激。
回答by Oleksiy Kononenko
After some research I solved my own problem. I used factory function to get desired selectItemById
selector. Here is my new selector:
经过一番研究,我解决了我自己的问题。我使用工厂函数来获得所需的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 {};
}
});
Then all I have to do in my controller is to call this selector and pass it an id of desired item to get the item out of the store:
然后我在我的控制器中要做的就是调用这个选择器并向它传递所需项目的 id 以将项目从商店中取出:
import * as selectors from '../../app/store/selectors';
this.store.select(selectors.getItemById(id))
.subscribe((item) => {
this.item = item;
});
回答by Maksym Shevchenko
Everything becomes much easier when using entities.
When you store them as an object, where key is an id
of item and value is the item itself. There are two ways for keeping items as an array - store only ids or full objects of Item.
使用实体时,一切都会变得容易得多。当您将它们存储为对象时,其中键是id
项目,值是项目本身。有两种方法可以将项目保存为数组 - 仅存储 Item 的 id 或完整对象。
in reducer:
在减速机中:
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]
}
in selectors:
在选择器中:
export const getItems = (state: ItemsState) => state.items;
export const getItemById = (id) => createSelector(
getItems,
(items) => items[id]
);
in container(component):
在容器(组件)中:
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)));
}
回答by Rahmathullah M
Based on the data available in the store:
根据商店提供的数据:
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;
}
}
);
Data that isn't available in the store:
商店中没有的数据:
To select a piece of state based on data that isn't available in the store you can pass propsto the selector function. These props gets passed through every selector and the projector function. To do so we must specify these props when we use the selector inside our component.
要根据 store 中不可用的数据选择一段状态,您可以将props传递给选择器函数。这些道具通过每个选择器和投影仪功能传递。为此,我们必须在组件内使用选择器时指定这些道具。
For example if we have a counter and we want to multiply its value, we can add the multiply factor as a prop:
例如,如果我们有一个计数器并且想要乘以它的值,我们可以添加乘法因子作为道具:
The last argument of a selector or a projector is the props argument, for our example it looks as follows:
选择器或投影仪的最后一个参数是 props 参数,对于我们的示例,它如下所示:
export const getCount = createSelector(
getCounterValue,
(counter, props) => counter * props.multiply
);
Inside the component we can define the props:
在组件内部,我们可以定义道具:
ngOnInit() {
this.counter = this.store.pipe(select(fromRoot.getCount, { multiply: 2 }))
}
Hers is the Documentation.
她是文档。