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]

额外:

.

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

或者Lodash keyBy

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

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

没关系。

问题3 - 将所有articleEntities作为ngFor的数组:这是一个不错的选择吗?还是有更好的选择吗?

articles存储在Array中。

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

没关系。

以上是关于NGRX - 使用哈希而不是数组来表示状态的主要内容,如果未能解决你的问题,请参考以下文章

从使用 NgRx 选择商店获取对象而不是列表

为啥使用 NGRX 而不是构造函数注入服务?

如何通过 Angular 中的 NGRX 减速器使用数组更新状态?

Ngrx 状态可变性

Angular 6 ngrx,如何将新项目添加到状态对象的数组中?

如何删除ngrx中以前的存储状态?