3

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.

9
  • will it be item.product.name or item.productName? Commented Aug 2, 2018 at 9:57
  • try to console.log(item.product) to see if thats undefined Commented Aug 2, 2018 at 9:58
  • 1
    item.product is undefined. Are you sure that all the items' product are set? Commented Aug 2, 2018 at 10:12
  • 1
    according to error your product is undefined Commented Aug 2, 2018 at 10:12
  • 1
    Shubham: The problem is the first cart object on the list doesn't have any product object in it. I try to figure how to empty that list. Commented Aug 2, 2018 at 10:30

2 Answers 2

4

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}
Sign up to request clarification or add additional context in comments.

Comments

2

There could be two possibilities 1. Your variable name is not correct or 2. Check for item is not empty and then you print something like below one

cart.items ? cart.items.map(your code)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.