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

时间:2018-09-15 21:13:16

标签: angular redux ngrx

实际上我正在使用NGRX(Angular的Redux)。开始时,我开始将实体存储为状态内的数组。阅读一些文章后,我想将我的实体存储为散列,而我认为使用id而不是过滤数组来访问实体的实体更有效。

但是我实际上不确定以正确的ngrx方式进行操作。

可以在这里随意检查我的(正在工作-但是最佳做法?)示例: Ngrx Articles Sample

在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的文章),我希望包含该文章的组件将被更新。

这是有效的变体还是有更好的选择和解决方案?随意将stackblitz示例与其他变体/代码段进行分叉。

谢谢!

2 个答案:

答案 0 :(得分:2)

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

第一季度:您的解决方案有效,我更喜欢使用reduce

第二季度:很好

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])

第4季度:确实要使用entities[id]

来选择特定实体

其他:

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

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

  • 自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>

答案 1 :(得分:1)

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

linked
  

问题0:什么是用id的数组保存数组的好用例?   Object.keys(hash)会给出相同的结果吗?

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

  

问题1:这是一个好选择吗?还是有更好的替代方法   创建哈希?

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' )
);

Lodash keyBy

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

  

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

没关系。

  

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

_.keyBy(action.payload, 'id' );存储在数组中。

  

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

我没事。