I have App.js with products and cart.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import ProductGrid from './components/ProductGrid';
import CartTable from './components/CartTable';
import { fetchProducts } from './state/product/actions';
import { fetchCart } from './state/cart/actions';
class App extends Component {
componentDidMount() {
this.props.fetchProducts();
this.props.fetchCart();
}
render() {
const {
isProductLoading,
products,
cart,
} = this.props;
if(isProductLoading) {
return <h2>loading...</h2>
}
return (
<div>
<h1>Shop application!</h1>
<ProductGrid
products={products}
/>
<h1>Cart</h1>
<CartTable
cart={cart}
/>
</div>
);
}
}
const getProductById = (products, productId) => products.find(p => p._id === productId);
const populateCartItems = (c, p) => ({
...c,
items: c.items.map(i => ({
...i,
product: getProductById(p, i.productId),
})),
});
const mapStateToProps = (state) => ({
isProductLoading: state.product.isLoading,
products: state.product.products,
cart: populateCartItems(state.cart.cart, state.product.products),
});
const mapDispatchToProps = {
fetchProducts,
fetchCart,
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
Problem is with the populate of cart and products objects.
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
const Wrapper = styled.table`
width: 100%;
border-collapse: collapse;
td, th {
border: 1px solid #DDD;
padding: 8px;
text-align: left;
}
tr:nth-child(even) {
background: #DDD;
}
`;
const CartTable = ({ cart }) => (
<Wrapper>
<thead>
<tr>
<th>Item Name</th>
<th>Item Price</th>
<th>Item Quantity</th>
</tr>
</thead>
<tbody>
{cart.items.map(item => (
<tr key={item.productId}>
<td>{item.product.name}</td>
<td>{}</td>
<td>{item.quantity}</td>
</tr>
))}
</tbody>
</Wrapper>
);
CartTable.propTypes = {
cart: PropTypes.shape({
items: PropTypes.arrayOf(PropTypes.shape({
product: PropTypes.shape({
name: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
}).isRequired,
productId: PropTypes.string.isRequired,
quantity: PropTypes.number.isRequired,
})).isRequired,
}).isRequired,
};
export default CartTable;
When passing cart object to CartTable, I get error:
TypeError: Cannot read property 'name' of undefined
30 | <tbody>
31 | {cart.items.map(item => (
32 | <tr key={item.productId}>
> 33 | <td>{item.product.name}</td>
34 | <td>{}</td>
35 | <td>{item.quantity}</td>
36 | </tr>
I'm quite sure the cart object is working fine in App.js (tested with console.log) but after it has passed to CartTable, populated product object is not found.
You're not validating your data before trying to render it. A simple fix for the problem would be to change your map function into:
{cart.items && !isProductLoading ? cart.items.map(item => (
<tr key={item.productId ? item.productId : null}>
<td>{item.product.name ? item.product.name : ''}</td>
<td>{}</td>
<td>{item.quantity ? item.quantity : null}</td>
</tr>
)) : null}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With