在 react-redux 中添加 eshop 中的数量

Add quantity in eshop in react-redux

我建立了一个网店并努力寻找语法来增加“购物车”中产品的数量。我已成功将产品“添加到购物车”,但未更新数量 添加的产品。每次我单击“addToCart”时它都会添加产品。我正在使用 redux,所以我知道我应该在 reducer 文件中编写额外的代码。 我的减速器文件代码如下:

import { ADD_TO_CART } from './constants'
import { REMOVE_FROM_CART } from './constants'


const initialState = {
    cart: [],
  }
const ShoppinReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TO_CART:
      const newCart = [...state.cart]
      
      newCart.push(action.payload)
      return {
        ...state,
        cart: newCart
      }

    case REMOVE_FROM_CART:
      const cart = [...state.cart]
      const updatedCart = cart.filter(item => item.id !== action.payload.id)
      return {
        ...state,
        cart: updatedCart
      }
    
    default:
    return state
  }
}
  export default ShoppinReducer

我的“购物车”组件如下:

import React, { Component } from "react"
import { Card, CardBody, CardHeader, CardTitle, Row, Col } from "reactstrap"
import PanelHeader from "components/PanelHeader/PanelHeader.js"
import { connect } from "react-redux";
import { removeCart} from "../redux/actions";


class Cart extends Component {
   removeFromCart = (product) => {
    const cartProducts = this.props.cart 
    const updatedCartProducts = cartProducts.filter(item => item.id !== product.id);
  
  }

  render () {
    const cartProducts = this.props.cart
    return (
      <>
        <PanelHeader size="sm" />
        <div className="content">
          <Row>
            <Col xs={12}>
              <Card>
                <CardHeader>
                  <CardTitle tag="h4">Products List</CardTitle>
                </CardHeader>
                <CardBody>
                <table class="table table-striped table-hover">
                  <thead>
                    <tr>
                      <th scope="col"><strong>#</strong></th>
                      <th scope="col"><strong>Name</strong></th>
                      <th scope="col"><strong>Code Item</strong></th>
                      <th scope="col"><strong>Quantity</strong></th>
                      <th scope="col"><strong>Price Total</strong></th>
                    </tr>
                  </thead>
                    <tbody>
                      {cartProducts.length > 0 && cartProducts.map((cartProduct, index) => (             
                      <tr key={cartProduct.id}>
                    <th scope="row">{index +1}</th>
                    <td>{cartProduct.title}</td>
                    <td>{cartProduct.code}</td>
                    <td>{cartProduct.quantity}</td>
                    <td>{cartProduct.price}</td>
                    <td><button onClick ={() => this.props.removeCart(cartProduct)} className="btn btn-danger cart-button px-4">Remove</button></td>
                      </tr>))}
                    </tbody>
                </table>
              </CardBody>
            </Card>
          </Col>
        </Row>
      </div>
    </>
    )
  }
}


const mapStateToProps = (state)=> {
  return {
      cart: state.cart
       }
  }

const mapDispatchToProps = (dispatch) => { 
      return {
        removeCart: (product) => {dispatch(removeCart(product))}
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Cart);

请记住,“addToCart”按钮存在于其他组件中,但是,我发布了“Cart”组件以显示“Cart”的结构! 提前致谢!

希望我能正确理解你的问题。我假设您的购物车状态是这样的

cart: [
  {itemId: '1', quantity: 1, price: 100, ...},
  {itemId: '2', quantity: 1, price: 200, ...}
]
问题是您现有的 addToCart 操作只会将一个项目推到数组的末尾,而不会检查这是否是购物车中已经存在的项目。最终购物车变成了

cart: [
  {itemId: '1', quantity: 1, price: 100, ...},
  {itemId: '2', quantity: 1, price: 200, ...},
  {itemId: '1', quantity: 1, price: 100, ...}
]

因此您需要检查您添加的是新商品还是现有商品,如果是现有商品,您需要更新现有商品数量而不是将其推送到数组。

您可以在执行 ADD_TO_CART 操作时检查该项目是否已在列表中。可能类似于

const alreadyInList = state.cart.find(item => item.id === action.payload.id);
let newCart;
if (alreadyInList) { // increments quantity if item already in list
  newCart = state.cart.map(item => {
    if (item.id === action.payload.id) {
      return {..item, quantity: item.quantity + 1};
    } else {
      return item;
    }
  });
} else { // adds item to the end if it's not already in the list
  newCart = [...state.cart, payload.action];
}
return {..state, cart: newCart};

但是,JavaScript 数组不是适合此类操作的数据结构。如果您使用的对象的键是产品 ID,而值是产品本身,那就更好了。然后你就可以检查一个项目是否已经存在并更有效地更新它。

旁注:

在映射列表之前检查 cartProducts 的长度

    {cartProducts.length > 0 && cartProducts.map((cartProduct, index) => (...

您不需要这样做,cartProducts.map((cartProduct, index) => (... 就足够了。

此外,您可以看看 React Hooks 和 Redux 工具包。这两者都有助于减少样板文件。

在将任何商品推送到您的购物车之前,您需要检查购物车中是否已存在该商品,如果存在则应更新数量。您可以将 reducer 中的 ADD_TO_CART 案例重写为如下内容:

const initialState = {
    cart: [],
  }
const ShoppinReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TO_CART:
      let newCart = [...state.cart]
      let itemIndex = state.cart.findIndex(obj=>obj.id===action.payload.id)  
      let currItem = state.cart[itemIndex]

      if(currItem){
            currItem.quantity = parseInt(currItem.quantity) + 1
            state.cart[itemIndex] = currItem
            newCart = [...state.cart]
        }
        else{
            
            newCart = newCart.concat(action.payload)
        }
        
        return {
          cart: newCart
        }

    case REMOVE_FROM_CART:
      const cart = [...state.cart]
      const updatedCart = cart.filter(item => item.id !== action.payload.id)
      return {
        ...state,
        cart: updatedCart
      }
    
    default:
    return state
  }
}

正如@spiritWalker 所说,您必须在减速器中实现该逻辑。我举个例子:

    case ADD_TO_CART:
      const newCart = [...state.cart]
      
      const index = newCart.findIndex((item) => item.id == action.payload.id)
      // If index is -1, no similar items were found so we 
      // add the item to the cart.
      // Otherwise, the index of the item is returned and we use
      // it to update the quantity property of the existing item.
      if (index == -1) {
        newCart.push(action.payload)
      } else {
        newCart[index].quantity++
      }
      
      return {
        ...state,
        cart: newCart
      }

此外,我建议您尝试一下 Redux Toolkit Package,它从 Redux 中抽象出大量逻辑和样板文件,绝对可以使您的代码更精简。

最终,以下代码运行良好。我 post 以防万一其他人需要它以备将来参考!

import { ADD_TO_CART } from './constants'
import { REMOVE_FROM_CART } from './constants'
// import { ADD_QUANTITY} from './constants'
// import { SUB_QUANTITY}  from './constants'
// import { EMPTY_CART}  from './constants'


const initialState = {
    cart: [],
  }
const ShoppinReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TO_CART:
      
      let newCart = [...state.cart]

      let itemIndex = state.cart.findIndex(obj=>obj.id===action.payload.id)
      
         
      let currItem = state.cart[itemIndex]

      if(currItem){
      currItem.quantity = parseInt(currItem.quantity) + 1
      state.cart[itemIndex] = currItem
      newCart = [...state.cart]
      }
      else {

      newCart = newCart.concat(action.payload)
      }

      return {
      cart: newCart
      }

    case REMOVE_FROM_CART:
      const cart = [...state.cart]
      const updatedCart = cart.filter(item => item.id !== action.payload.id)
      return {
        ...state,
        cart: updatedCart
      }
    
    default:
    return state
  }
}
  export default ShoppinReducer