NGRX - 使用哈希而不是数组作为状态



实际上我正在使用NGRX(Redux for Angular(。一开始,我已经开始将我的实体存储为状态中的数组。阅读了一些文章后,我想将我的实体存储为哈希,而我认为使用 id 访问实体实体而不是过滤数组的性能更高。

但我实际上不确定这样做是否正确 ngrx。

请随时在此处查看我的(工作 - 但最佳实践?(示例: Ngrx 文章示例

在 articles.component 中,您将找到一个 articleReducer 和一个 ArticlesComponent,它们将使用存储来获取所有文章并获取一篇具体文章。

对于每个不确定的部分,我都有评论,问题 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(,我希望包括文章在内的组件将被更新。

这是有效的变体还是有更好的选择、解决方案?随意使用其他变体/代码片段分叉堆栈闪电战示例。

谢谢!

Q0:ids属性可用于指示排序。另一点是,如果您删除一个实体,只需将其从 this 数组中删除就足够了,与从字典中删除它相比,这是一项更简单的任务。

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),
};

Q3:在你的选择器中,你确实应该把它转换为一个数组。如果您使用的是ids属性(请参阅答案 1(,则应使用ids.map(id => entities[id])

Q4:确实要选择特定实体使用entities[id]

额外:

  • NgRx 有一个以这种方式处理状态的包@ngrx/实体 - unsorted_state_adapter.ts - state_selectors.ts

  • 与其使用this.store.pipe(select('articles', 'articleEntities'))选择数据,我认为您应该看看 NgRx 选择器,恕我直言,它更干净。

  • 从 Angular 6.1 开始,您还可以在带有键值管道的字典上使用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>

如果顺序很重要 - 使用数组作为属性 不能保证对象中的顺序。 为了优化在数组中的查找,我们可以创建将数组转换为对象的选择器。 最好保持状态规范化(无需保留我们可以从其他人那里计算的值(。

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:当 对象键(哈希(会给出相同的吗?

使用数组和选择器将数组转换为对象

问题1:这是一个好的选择吗?或者有更好的选择 创建哈希?

action.payload.reduce((hash, article) =>({...hash, [article.id]: article}), {});

或洛达什键通过

_.keyBy(action.payload, 'id' );

问题2:这是一个好的选择吗?还是有更好的选择?

还行。

问题 3 - 将所有文章实体作为 ngFor 的数组获取:这是 一个不错的选择?还是有更好的选择?

articles存储在数组中。

问题 4 - 为给定 id 获取一篇具体文章:这是一个 好选择?还是有更好的选择?

我不行。

最新更新