Angular 14 NGRX Selector编写报错,如何移除单条同ID购物车商品?
问题排查与解决方案
一、Selector报错原因
你写的Selector存在三个核心问题:
- createSelector语法错误:它的标准用法是先传入输入选择器数组,再传入转换函数,你直接传单个函数不符合API规范。
- indexOf用法错误:
state是Photo对象数组,state.indexOf(id)是在找数组中是否存在等于数字id的元素,而非photo.id === id的对象,永远会返回-1。 - 额外参数处理错误:要接收
id这类额外参数,需要在输入选择器中通过第三个参数获取。
二、正确的Selector实现
如果确实需要获取第一个匹配ID的索引,正确的Selector写法如下:
import { createSelector } from '@reduxjs/toolkit'; export const basketPosition = createSelector( // 输入选择器1:获取购物车数组 (state: Array<Photo>) => state, // 输入选择器2:获取传入的id参数 (_state: Array<Photo>, { id }: { id: number }) => id, // 转换函数:计算第一个匹配的索引 (basket, id) => basket.findIndex(photo => photo.id === id) );
三、移除单个同ID商品的Reducer实现
其实不需要额外Selector,直接在Reducer里处理更简洁,推荐两种immutable的实现方式:
方案1:findIndex + 数组切片(性能更优)
on(getBasket, (state, { id }) => { const targetIndex = state.findIndex(photo => photo.id === id); // 没找到对应商品则返回原数组 if (targetIndex === -1) return state; // 拼接新数组,跳过目标索引的元素 return [...state.slice(0, targetIndex), ...state.slice(targetIndex + 1)]; });
方案2:reduce构建新数组
on(getBasket, (state, { id }) => { let hasRemoved = false; return state.reduce((newBasket, photo) => { // 只移除第一个匹配的商品 if (photo.id === id && !hasRemoved) { hasRemoved = true; return newBasket; } newBasket.push(photo); return newBasket; }, [] as Photo[]); });
原代码问题说明
你用的state.filter(photo => photo.id !== id)会过滤掉所有id匹配的元素,所以当购物车中有多个同ID商品时,会全部被移除。上面的两种方案只会移除第一个匹配的商品,符合你的需求。
内容的提问来源于stack exchange,提问作者bilpor
相关产品推荐
相关产品推荐

