在Reactjs(带有redux / thunk)中,如何获取购物车中所有项目的总成本

时间:2018-07-29 19:04:36

标签: javascript reactjs redux react-redux cart

我正在建立一个包含物品清单的购物车。用户可以更新每个项目的数量,从而调整项目的价格。 同样在购物车的底部,用户必须支付的所有价格的总和应为总计

我的问题是如何获取所有更新的价格,对其进行汇总并显示总计。当用户更改每件商品的数量时,如何使总计进行自我更新?

反应(项目):

class Item extends Component {
  constructor(props) {
    super(props);

    this.state = {
      quantity: 1,
      price: parseFloat(this.props.product.price.replace(/\$|£|/g, '')).toFixed(2)
    };

    this.onChangeHandler = this.onChangeHandler.bind(this);
  }

  onChangeHandler(event) {
    const target = event.target;
    this.props.updateSubtotal(this.props.product.price, event.target.value);
    this.setState((prevState, props) => ({
      quantity: target.value,
      price: props.subtotal
    }));
  }

  render() {
    const { product, index } = this.props;

    return (
      <li>
        <h3>{product.name}</h3>
        <Input
          onChange={this.onChangeHandler}
          name="product-quantity"
          value={this.state.quatity}
        />
        <span>
          {'$' + this.state.price}
        </span>
      </li>
    );
  }
}

const mapStateToProps = state => ({
  subtotal: state.products.subtotal
});

export default connect(mapStateToProps, { updateSubtotal })(Item);

Redux(操作):

// UPDATE TOTAL PRICE
export const updateTotal = result => dispatch => {

  // Don't what to do here. Or maybe there's a better solution...
  const newTotal = [];
  newTotal.push(result);

  return dispatch({
    type: UPDATE_TOTAL,
    total: newTotal
  });
};

// UPDATE ITEM PRICE BY QUANTITY
export const updateSubtotal = (price, multiplier) => dispatch => {
  const result = computePrice(price, multiplier);

  // Update cart total      
  dispatch(updateTotal(result));

  return dispatch({
    type: UPDATE_SUBTOTAL,
    subtotal: result
  });
};

Redux(减速器):

const INITIAL_STATE = {
  total: [],
  subtotal: 1,
  products: [],
  loading: false
};

const productsReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    // Update item price
    case Types.UPDATE_SUBTOTAL:
      return {
        ...state,
        subtotal: action.subtotal
      };

    // Update total
    case Types.UPDATE_TOTAL:
      return {
        ...state,
        total: action.total // -> I'm stuck here
      };

    default:
      return state;
  }
};

export default productsReducer;

1 个答案:

答案 0 :(得分:-1)

您无需使用其他操作即可更新总价。每当您将新商品添加到购物车时,您的状态都会更改,是吗?在这种情况下,您只需要编写一个看起来像这样的util:

// utils.js

export const totalPrice = (state) => {
    const products = state.products;
    const reducer = (currentTotal, product) => currentTotal + product.price;
    return products.reduce(reducer);
};

然后,在您的容器中执行以下操作:

// Cart.js

import React from 'react';
import { connect } from 'react-redux';

import { totalPrice } from './utils'; // or wherever else

const Cart = ({ total }) => (
    <div>
        {`Your total is ${total}`}
    </div>
);

const mapStateToProps = state => ({
    total: totalPrice(state),
});

export default connect(
    mapStateToProps,
)(Cart);

每当您向products添加商品时,价格就会自动更新。

** EDIT **

根据您在注释中的要求,如果您想将total保留在减速器中,则这是另一种方法。请注意,您将不再需要执行updateTotal操作。

// reducers.js

const INITIAL_STATE = {
    total: 0, // note this is not an array.
    subtotal: 0,  // I also set this to 0 instead.
    products: [],
    loading: false
};

const productsReducer = ( state = INITIAL_STATE, action ) => {
    switch(action.type) {
    case Types.UPDATE_SUBTOTAL:
        const newSubtotal = action.subtotal;
        const newTotal = state.total + (newSubtotal - state.subtotal);
        return {
            ...state,
            subtotal: newSubtotal,
            total: newTotal,
        };
    }
    default:
        return state;
};

即使上述方法可行,我还是建议您调度一个操作来更新products而不是价格,并更新该操作所导致的所有相关内容。如果您考虑一下,每当将商品添加到products时,更新总价/小计价格,数量等是很有意义的。

另一件事:您在化纸机中使用的印象spread syntax对我来说是浅拷贝。您需要注意存储在products数组中的内容,以免错误地改变旧状态。请记住,您始终想返回一个新的状态对象。您可以了解有关here的更多信息。