使用Redux计算多个项目



我正在尝试用Redux实现一个购物车。我的React代码从数据库中获取产品信息,并将其呈现给用户查看。这是我的App.js:的样本

function GetProductsHtml() {
initProducts()
const AddItem = (ProductID) => {
store.subscribe(() => console.log(store.getState()));
store.dispatch(AddItemToCart())
}
return products.map(products =>
<div key={products.ProductID}>
<h2>{products.ProductName}</h2>
<h2>{products.ProductDescription}</h2>
<h2>{products.ProductQuantity} units available</h2>

<button onClick={AddItem(products.ProductID)}>Add to cart</button>
</div>
);
}

利用该代码,每个产品得到";添加到购物车";按钮,但问题是它们都增加了一个计数器,所以我尝试将ProductID作为参数传递给我的Redux reducer。这是我的cart.js:

export const AddItemToCart = (productID) => {
return {
type: 'ADDITEMTOCART',
productID
}
}
export const DeleteItemFromCart = (productID) => {
return {
type: 'DELETEITEMFROMCART',
productID
}
}
export const Counter = (state = [], action) => {
switch (action.type) {
case 'ADDITEMTOCART':
state.push({
key:   action.productID,
value: value + 1
});
return state;
case 'DELETEITEMFROMCART':
state.push({
key:   action.productID,
value: value - 1
});
return state;
}
}

正如您所看到的,我已经尝试使用具有键值对的dictionary(ProductID是键,quantity是值(。但是巴贝尔没有编译,他说";值未定义";。如有任何建议,我们将不胜感激。提前谢谢。

正如您所看到的,我尝试使用带有键值对的dictionary(ProductID是键,quantity是值(。

存储最少量的必要数据总是明智的,所以您在这里有正确的想法。问题是它没有得到正确的实施。让我们将状态设置为从id映射到数量的单个对象,而不是键值对象的数组。它应该是这样的:

{
123: 1, // cart contains 1 of product id #123
999: 2, // cart contains 2 of product id #999
}

在编写减少程序时,因为函数很重要,所以必须永远不要更改状态。您需要始终返回复制的版本。因此,您不能调用.push()(您将使用.concat()来添加数组项(。

export const Counter = (state = {}, action) => {
switch (action.type) {
case 'ADDITEMTOCART':
return {
...state, // copy all other quanities
// update this property by adding 1 to the current quanity
// or just add with quantity 1 if it didn't already exist
[action.productID]: ( state[action.productID] || 0 ) + 1
}
case 'DELETEITEMFROMCART':
return {
...state,
[action.productID]: ( state[action.productID] || 1 ) - 1
}
default:
return state;
}
}

请注意,我们可能有0数量的购物车条目,因此您可能希望在渲染之前将其过滤掉。


有一种更简单的方法来编写reducer,那就是使用Redux Toolkit。使用该工具包,您的reducer可以在状态的草稿版本上进行突变。您不需要返回新状态。您只需更改要更改的属性。

如果您确信action.payload中的id已经存在于购物车中,那么您只需写入state[action.payload]++;state[action.payload]--;即可更改数量。但是,如果密钥还不在对象中,那么通过执行此操作可以获得NaN。所以我们必须检查一下。

它还使动作创建者自动发挥作用!请注意,它们使用属性payload而不是productID

const cartSlice = createSlice({
name: "cart",
initialState = {},
reducers: {
// increase the cart quantity by 1
addItemToCart(state, action) {
// the current cart quantity - is 0 if not in cart
const currentAmount = state[action.payload] ?? 0;
state[action.payload] = currentAmount + 1;
},
// decrease the cart quantity by 1
decrementQuantity(state, action) {
// subtract 1 from quantity if there are multiple in the cart
if (state[action.payload] > 1) {
state[action.payload]--;
}
// delete from cart if the quantity was 1 (or not found)
else {
delete state[action.payload];
}
},
// remove this product from the cart entirely
deleteItemFromCart(state, action) {
delete state[action.payload];
}
}
});
// export action creators
export const { addItemToCart, decrementQuantity, deleteItemFromCart } = cartSlice.actions;
// export reducer
export default cartSlice.reducer;

让我们假设您的商店有cartproducts的减速器。因此,购物车数据将位于state.cart

以下是组件的外观:

// component that displays a single product
function RenderProduct({ product }) {
// access the dispatch function from a hook
const dispatch = useDispatch();
// can get cart information via a selector
// get the number of this item already in the cart
const numberInCart = useSelector((state) => state.cart[product.ProductID]);
return (
<div>
<h2>{product.ProductName}</h2>
<h2>{product.ProductDescription}</h2>
<h2>{product.ProductQuantity} units available</h2>
{product.ProductQuantity > 1 ? (
<button onClick={() => dispatch(addItemToCart(product.ProductID))}>
Add to cart
</button>
) : (
"Sold Out"
)}
</div>
);
}
function ProductsList() {
const dispatch = useDispatch();
// some selector that gets the products array
const products = useSelector((state) => state.products);
useEffect(() => {
// some action that loads products into the state
dispatch(loadProductData());
}, [dispatch]);
return (
<div>
{(products || []).map((product) => (
<RenderProduct key={product.ProductID} product={product} />
))}
</div>
);
}

表达式value-1和value+1中的value关键字就是问题所在。未定义value关键字。因此,要增加/减少特定产品的数量,需要找到当前的数量。在这里,如果是增量,首先,如果数组中不存在该项目,则需要找到该项目并更新该项目的数量,只需添加该项目,当减少数量时,如果数量已经小于1,则需要查找该项目,删除该项目,否则减少数量。

export const Counter = (state = [], action) => {
switch (action.type) {
case 'ADDITEMTOCART':
let itemIndex = state.findIndex(x => x.productID == action.productID);
if(itemIndex != -1){
state.push({
key:   action.productID,
value: value + 1
});
} else {
state[itemIndex].value +=1; 
}
return [...state];
case 'DELETEITEMFROMCART':
let itemIndex = state.findIndex(x => x.productID == action.productID);
state[itemIndex].value -=1;
if(state[itemIndex].value == 0){
state.splice(itemIndex, 1);
}
return [...state];
}
}

相关内容

  • 没有找到相关文章

最新更新