React.js中无法计算购物车所有商品总金额的问题求助
Hey there! Let's sort out that total amount calculation problem you're facing. You’ve already nailed the product list, quantity controls, and individual subtotals—nice work so far!
The issue right now is that your total state lives inside the individual Product component, which means each component can only track its own value, not the sum of all products. To calculate the grand total, we need to centralize the state of all products so we can easily sum up their subtotals.
Here are two common approaches depending on your component structure:
Approach 1: Single Component Manages All Products
If your Product component is responsible for rendering the entire list, update it to store all product data in its state, then calculate the total using the reduce method.
Updated Products.js Code:
import React from 'react'; import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; import PropTypes from 'prop-types'; import './App.css'; const btn_style = { cursor: "pointer" } export default class Product extends React.Component { constructor(props) { super(props); // Store all product data (including quantity) in state this.state = { products: [ { id: 1, name: "Product A", price: 15, count: 1 }, { id: 2, name: "Product B", price: 25, count: 1 }, { id: 3, name: "Product C", price: 30, count: 1 } // Add more products as needed ] }; } // Handle quantity changes for a specific product handleQuantityChange = (productId, change) => { this.setState(prevState => { const updatedProducts = prevState.products.map(product => { if (product.id === productId) { // Ensure quantity doesn't drop below 1 const newCount = Math.max(1, product.count + change); return { ...product, count: newCount }; } return product; }); return { products: updatedProducts }; }); } // Calculate grand total by summing all subtotals calculateGrandTotal = () => { return this.state.products.reduce((total, product) => { return total + (product.price * product.count); }, 0); } render() { const grandTotal = this.calculateGrandTotal(); return ( <div> <Table> <TableHeader> <TableRow> <TableHeaderColumn>Product</TableHeaderColumn> <TableHeaderColumn>Price</TableHeaderColumn> <TableHeaderColumn>Quantity</TableHeaderColumn> <TableHeaderColumn>Subtotal</TableHeaderColumn> </TableRow> </TableHeader> <TableBody> {this.state.products.map(product => ( <TableRow key={product.id}> <TableRowColumn>{product.name}</TableRowColumn> <TableRowColumn>${product.price}</TableRowColumn> <TableRowColumn> <button style={btn_style} onClick={() => this.handleQuantityChange(product.id, -1)}>-</button> <span> {product.count} </span> <button style={btn_style} onClick={() => this.handleQuantityChange(product.id, 1)}>+</button> </TableRowColumn> <TableRowColumn>${product.price * product.count}</TableRowColumn> </TableRow> ))} </TableBody> </Table> <div style={{ marginTop: "20px", fontSize: "1.2rem", fontWeight: "bold", textAlign: "right" }}> Grand Total: ${grandTotal} </div> </div> ); } }
Approach 2: Parent Component Manages State (For Multiple Product Components)
If you're rendering multiple Product components from a parent (like App.js), lift the product state up to the parent. Each Product will use a callback to notify the parent of quantity changes, and the parent will calculate the total.
Parent Component (App.js):
import React from 'react'; import Product from './Products'; import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow } from 'material-ui/Table'; class App extends React.Component { constructor(props) { super(props); this.state = { products: [ { id: 1, name: "Product A", price: 15, count: 1 }, { id: 2, name: "Product B", price: 25, count: 1 } ] }; } handleQuantityUpdate = (productId, change) => { this.setState(prevState => { const updatedProducts = prevState.products.map(product => { if (product.id === productId) { const newCount = Math.max(1, product.count + change); return { ...product, count: newCount }; } return product; }); return { products: updatedProducts }; }); } calculateTotal = () => { return this.state.products.reduce((total, product) => total + (product.price * product.count), 0); } render() { const total = this.calculateTotal(); return ( <div> <Table> <TableHeader> <TableRow> <TableHeaderColumn>Product</TableHeaderColumn> <TableHeaderColumn>Price</TableHeaderColumn> <TableHeaderColumn>Quantity</TableHeaderColumn> <TableHeaderColumn>Subtotal</TableHeaderColumn> </TableRow> </TableHeader> <TableBody> {this.state.products.map(product => ( <Product key={product.id} product={product} onQuantityChange={this.handleQuantityUpdate} /> ))} </TableBody> </Table> <div style={{ marginTop: "20px", fontWeight: "bold", textAlign: "right" }}> Total: ${total} </div> </div> ); } } export default App;
Updated Products.js:
import React from 'react'; import { TableRow, TableRowColumn } from 'material-ui/Table'; import PropTypes from 'prop-types'; import './App.css'; const btn_style = { cursor: "pointer" } export default class Product extends React.Component { render() { const { product, onQuantityChange } = this.props; const subtotal = product.price * product.count; return ( <TableRow> <TableRowColumn>{product.name}</TableRowColumn> <TableRowColumn>${product.price}</TableRowColumn> <TableRowColumn> <button style={btn_style} onClick={() => onQuantityChange(product.id, -1)}>-</button> <span> {product.count} </span> <button style={btn_style} onClick={() => onQuantityChange(product.id, 1)}>+</button> </TableRowColumn> <TableRowColumn>${subtotal}</TableRowColumn> </TableRow> ); } } // Define prop types for clarity Product.propTypes = { product: PropTypes.shape({ id: PropTypes.number.isRequired, name: PropTypes.string.isRequired, price: PropTypes.number.isRequired, count: PropTypes.number.isRequired }).isRequired, onQuantityChange: PropTypes.func.isRequired };
Key Takeaway
By centralizing your product state (either in the list component or a parent), you gain access to all product data needed to calculate the grand total. The reduce method is perfect here—it iterates over the products array and accumulates the sum of each subtotal.
内容的提问来源于stack exchange,提问作者Swathi kanduri

