在React / Redux中,如何计算购物车的总价

Sha*_*aoz 2 javascript reactjs redux react-redux

我已经在Google和SO上搜索了解决方案,但仍然找不到答案。它们都停止在“将商品添加到购物车”或“增加/减少数量”处,但从不计算总数,这很烦人!

在我的应用中,有一个商品列表,用户可以在其中输入商品的数量,这会更新其价格。我只想知道如何使用Redux 将购物车中所有项目的所有价格汇总为总价,并将其显示在我的React应用中?

另外,如果您可以将我引向任何超出购物车中列出产品范围的良好购物车教程,我都会很高兴。

行动:

/**
 * @description UPDATE SINGLE ITEM PRICE WHEN USER ENTER QUANTITY
 *
 * @param{number} price
 * @param{number} quantity - enter by user from input
 */
export const updateItemPrice = (price, quantity) => dispatch => {
  const result = price * quantity;

  return dispatch({
    type: UPDATE_ITEM_PRICE,
    subtotal: result
  });
};
Run Code Online (Sandbox Code Playgroud)

减速器:

const INITIAL_STATE = {
  total: 0,
  subtotal: 0
};

const productsReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    // Update single item price
    case Types.UPDATE_ITEM_PRICE:
      return {
        ...state,
        subtotal: action.subtotal,
        total: // --> Here is where I'm stuck!!
      };

    default:
      return state;
  }
};
Run Code Online (Sandbox Code Playgroud)

Zai*_*uch 6

编辑:状态/动作/归约器的更完整示例。

您是否真的需要将总计存储在redux中?通常,您希望将最小状态保留在redux中,并计算可以在选择器中使用的所有派生数据。小计和总计肯定属于此类别(除非您有非常不同寻常的设置自己的价格设置或其他东西),因此您可以根据需要计算它们,而不是将其存储在商店中,例如作为mapStateToProps函数的一部分(假设您正在使用react-redux)。

这是您的状态看起来的示例。它包括两个主要部分,一个主要用于物品分类,第二个专门用于卡片。

{
  itemDetails: {
    item01: { name: 'Item One', price: 9.95 },
    item02: { name: 'Item Two', price: 10 },
    item03: { name: 'Item not appearing in this example', price: 50 },
  },
  cart: {
    item01: 1,
    item02: 2,
  },
}
Run Code Online (Sandbox Code Playgroud)

查看购物车切片,所有需要做的减速器都是管理购物车中的数量,您可以使用基本操作来完成此操作。动作和减速器可能看起来像(没有经过测试,只是为了提供这种感觉):

// Cart actions
const incrementQuantityInCart = (itemId) => ({
  type: 'incrementQuantityInCart',
  itemId,
})

const decrementQuantityInCart = (itemId) => ({
  type: 'decrementQuantityInCart',
  itemId,
})

const removeItemFromCart = (itemId) => ({
  type: 'removeItemFromCart',
  itemId,
})

// Cart reducer, would be combined with a separate reducer using redux's `combineReducers`
const cart = (state = {}, action) => {
  switch (action.type) {
    case 'incrementQuantityInCart':
      const currentQuantity = state[action.itemId] || 0
      return {
        ...state,
        [action.itemId]: currentQuantity + 1,
      }
    case 'decrementQuantityInCart':
      const currentQuantity = state[action.itemId] || 0
      return {
        ...state,
        [action.itemId]: Math.max(currentQuantity - 1, 0),
      }
    case 'removeItemFromCart':
      return {
        ...state,
        [action.itemId]: 0,
      }
    default:return state
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以有一个选择器,例如:

function getCartContents(state) {
  const itemsInCart = Object.keys(state.cart)
    .filter(itemId => state.cart[itemId] > 0)
    .map(itemId => {
      const quantity = state.cart[itemId]
      const itemDetail = state.itemDetails[itemId]

      return {
        name: itemDetail.name,
        price: itemDetail.price,
        quantity,
        subtotal: itemDetail.price * quantity,
      }
    })

  const total = itemsInCart.reduce((total, item) => total + item.subtotal)

  return { itemsInCart, total }
}

// example output based on the above state
// {
//   itemsInCart: [
//     {
//       name: 'Item One',
//       price: 9.95,
//       quantity: 1,
//       subtotal: 9.95,
//     },
//     {
//       name: 'Item Two',
//       price: 10,
//       quantity: 2,
//       subtotal: 20,
//     },
//   ],
//   total: 29.95,
// }
Run Code Online (Sandbox Code Playgroud)

然后,您可以在其中使用此函数mapStateToProps,也可以将其用作所需的任何组件,并且该组件将有权访问其道具中的此数据,因此可以根据需要使用。