NGRX - 使用哈希而不是数组来表示状态
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NGRX - 使用哈希而不是数组来表示状态相关的知识,希望对你有一定的参考价值。
实际上我正在使用NGRX(Redux for Angular)。一开始我已经开始将我的实体存储为我的状态中的数组。在阅读了一些文章之后,我想将我的实体存储为哈希,而我认为使用id而不是过滤数组更有效地访问实体实体。
但我实际上不确定正确的ngrx方式。
请随意查看我的(工作 - 但最佳实践?)示例:Ngrx Articles Sample
在articles.component中你会找到一篇articleReducer和一个ArticlesComponent,它将使用商店获取所有文章并获得一篇具体文章。
对于每个不确定的部分,我用QUESTION x评论 - ...
如果您不想查看完整的示例,请参阅以下问题片段:
问题0:
export const initialState: ArticleState = {
foo: 'bar',
articlesById: [], // QUESTION 0: What is a good usecase to hold an array with the id's when Object.keys(hash) will give the same?
articleEntities: {}
}
问题1 + 2:
case GET_ALL_ARTICLES: {
// QUESTION 1: is this a good choice? Or is there a better alternative to create the hash?
const articleHash: { [id: number]: Article} = {};
action.payload.forEach(article => articleHash[article.id] = article);
return {
...state,
// QUESTION 2: is this a good choice? Or is there a better alternative?
articlesById: action.payload.map(article => article.id),
articleEntities: articleHash
}
}
问题3:
// QUESTION 3 - Getting all articleEntities as Array for ngFor : is this a good choice? Or is there a better alternative?
this.articles$ = this.store.pipe(
select('articles', 'articleEntities'),
map(entities => Object.keys(entities).map(id => entities[id]))
);
问题4:
const givenIdByRouterMock = 2;
// QUESTION 4 - Getting one concrete Article for given id : is this a good choice? Or is there a better alternative?
this.article$ = this.store.pipe(
select('articles', 'articleEntities'),
map(entities => entities[givenIdByRouterMock])
);
如果我将使用新操作更新一些文章(例如,使用id 2),我希望包含文章的组件将被更新。
这是有效的变体还是有更好的选择,解决方案?随意将stackblitz示例与其他变体/代码片段分开。
谢谢!
Q0:ids
属性可用于表示排序。另一点是,如果删除一个实体,只需从该数组中删除它就足够了,与从字典中删除它相比,这是一个更简单的任务。
Q1:您的解决方案有效,我更喜欢使用reduce
Q2:没关系
return {
products: action.payload.products.reduce((dict, product) => {
dict[product.sku] = product;
return dict;
}, {}),
productSkus: action.payload.products.map(product => product.sku),
};
问题3:在您的选择器中,您确实应该将其转换为数组。如果您使用的是ids
属性(请参阅答案1),您应该使用ids.map(id => entities[id])
。
Q4:确实选择一个特定的实体使用entities[id]
额外:
- NgRx有一个包@ngrx/entity,以这种方式处理状态 - unsorted_state_adapter.ts - state_selectors.ts
- 而不是选择
this.store.pipe(select('articles', 'articleEntities'))
的数据,我认为你应该看看NgRx selectors,这是更清洁的imho。 - 从Angular 6.1开始,你也可以在带有keyvalue管道的字典上使用
ngFor
。
.
<mat-nav-list>
<a *ngFor="let member of familyMembers | async | keyvalue"
mat-list-item [routerLink]="['/groceries', member.key]">
{{ member.value.avatar }} {{member.value.name}}
</a>
</mat-nav-list>
如果订单很重要 - 在对象is not guaranteed中使用Array作为属性顺序。为了优化在Array中的查找,我们可以创建将Array转换为Object的选择器。保持状态标准化更好(不需要保留我们可以从其他人计算的值)。
export interface ArticleState {
foo: string;
articles: Article[];
}
export const selectFeature = (state) => state.articleState;
export const selectFeatureArticles = createSelector(selectFeature, state => state.articles);
export const selectFeatureArticlesMap = createSelector(
selectFeatureArticles,
articles => _.keyBy(articles, 'id' )
);
问题0:当Object.keys(hash)给出相同的值时,用id来保存数组的好用例是什么?
使用将Array转换为Object的Array和selector
问题1:这是一个不错的选择吗?或者是否有更好的替代方法来创建哈希?
action.payload.reduce((hash, article) =>({...hash, [article.id]: article}), {});
_.keyBy(action.payload, 'id' );
问题2:这是一个不错的选择吗?还是有更好的选择吗?
没关系。
问题3 - 将所有articleEntities作为ngFor的数组:这是一个不错的选择吗?还是有更好的选择吗?
将articles
存储在Array中。
问题4 - 为给定的id获取一个具体的文章:这是一个不错的选择吗?还是有更好的选择吗?
没关系。
以上是关于NGRX - 使用哈希而不是数组来表示状态的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 Angular 中的 NGRX 减速器使用数组更新状态?