Angular 14 NGRX 选择器问题

huangapple go评论49阅读模式
英文:

Angular 14 NGRX Selector issue

问题

在我的购物篮存储中,您可以看到我有5个物品,其中2个具有ID为4。

在我的reducer中,如果我使用以下代码:

on(getBasket, (state, { id }) => state.filter((photo) => photo.id !== id))

这在某种程度上是有效的,因为购物篮中的物品将被删除,如果购物篮中只有1个特定ID的物品,这是可以接受的。但在这种情况下,上述代码将从购物篮中删除2个条目。所以,为了只删除1个,我需要引入一个选择器来获取ID为4的第一个索引位置(我不关心删除哪一个)。

所以我尝试编写以下代码:

export const basketPosition = createSelector(
  (state: Array<Photo>, { id }: any) => state.indexOf(id)
)

其中state将是购物篮,id将是4。然而,整个语句被标记为红色,我看不出这个语句有什么问题。它一直显示以下错误信息:

源具有1个元素,但目标需要3个。

英文:

So in my basket store you can see that I have 5 items 2 have an id 0f 4.
Angular 14 NGRX 选择器问题

in my reducer, if I use:

 on(getBasket, (state, { id }) =&gt;  state.filter((photo) =&gt; photo.id !== id)

this works as far as it goes in that the item in the basket will be removed which is fine if I only have 1 item of a particular id in the basket otherwise in this scenario the above will remove 2 entries from the basket. So to only remove 1 I need to introduce a selector to obtain the first index position for id 4 in this case (I dont care which one is removed).

So I have attempted to write:

export const basketPosition = createSelector(
  ((state: Array&lt;Photo&gt;, { id }: any) =&gt; { return state.indexOf(id) })
  )

Where state will be basket, and the id would be 4. However The whole statement red lines and I cannot see what is wrong with that statement. it just keeps stating:

> Source has 1 element(s) but target requires 3.

答案1

得分: 0

你如何提供stateid给选择器basketPositioncreateSelector()需要一些状态来从中选择内容,根据你的示例,可以像下面这样:

export interface Things {
  basket: Basket[];
  selectedPhotos: Photos[];  
}

// 从状态中选择特定数据
export const selectBasket = (state: Things) => state.basket;
export const selectPhotos = (state: Things) => state.selectedPhotos;

// 从`selectPhotos`数据数组中返回第一个元素
export const selectOnePhoto = createSelector(selectPhotos, (photos: Photos[]) => photos[0]);

// 从`selectBasket`数据数组中返回所有元素
export const selectAllItems = createSelector(selectBasket, (basket) => basket);

如果需要向选择器传递参数,可以像下面这样提供一个(或多个):

export const selectItemById = (id: string) => createSelector(
  selectBasket,
  (basket) => {
   // ... 这里添加一些逻辑...   
   return basket.find(b => b.id === id);
  }
)

// 从组件中调用它

item$!: Observable<Item | undefined>;

ngOnInit(): void {
  this.item$ = this.store.select(selectBasket('someId'));
}
英文:

How are you providing state and id to the selector basketPosition...? createSelector() needs some State in order to select something from it, giving your example, it could be like the following:

export interface Things {
  basket: Basket[];
  selectedPhotos: Photos[];  
}

// selecting a specific data from the state
export const selectBasket = (state: Things) =&gt; state.basket;
export const selectPhotos = (state: Things) =&gt; state.selectedPhotos;


//from `selectPhotos` data array, return the first element
export const selectOnePhoto = createSelector(selectPhotos, (photos: Photos[]) =&gt; photos[0]);

//from the selectBasket data array, return all elements
export const selectAllItems = createSelector(selectBasket, (basket) =&gt; basket);

If you require to pass an argument to a selector, you can provide one (or many) like the following:

export const selectItemById = (id: string) = createSelector(
  selectBasket,
  (basket) =&gt; {
   // ... some logic here...   
   return basket.find(b =&gt; b.id === id);
  }
)

// calling it from a component

item$!: Observable&lt;Item | undefined&gt;;

ngOnInit(): void {
  this.item$ = this.store.select(selectBasket(&#39;someId&#39;));
}

答案2

得分: 0

我已经弄清楚了如何在购物篮中删除多个相同项目中的单个项目。所以我创建了一个操作:

export const removeFromBasket = createAction('[Basket Component] removeFromBasket', props<{ id: number }>());

然后我创建了一个减速器:

on(removeFromBasket, (state, { id }) => {
    const basketArray = [...state];
    basketArray.splice(state.findIndex(tt => tt.id === id), 1);
    return basketArray;
}),

然后在我的组件中调用减速器:

RemoveFromBasket(photo: Photo) {
    this.basketStore.dispatch(removeFromBasket({ id: photo.id }));
}
英文:

Ok, Took me a while but I have figured out how to remove a single item from my basket when I have multiple of the same item.

So I create an action:

export const removeFromBasket = createAction(&#39;[Basket Component] removeFromBasket&#39;, props&lt;{ id: number }&gt;());

then I create a reducer:

on(removeFromBasket, (state, { id }) =&gt; {
    const basketArray = [...state];
    basketArray.splice(state.findIndex(tt =&gt; tt.id === id), 1);
    return basketArray;
    }
  ),

then in my component I call the reducer :

RemoveFromBasket(photo: Photo) {
    this.basketStore.dispatch(removeFromBasket({ id :photo.id }));
  }

huangapple
  • 本文由 发表于 2023年2月23日 22:28:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/75546173.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定