javascriptreactjscommerce

TypeError: Cannot read properties of undefined (reading 'requestContent')


I am facing the issue in my react application.

TypeError: Cannot read properties of undefined (reading 'requestContent')

I am using commercejs in my application. The code points to isEmpty=!cart.line_items.length;. When checked it shows the proper value. Furthermore, I have noticed that the Api returns NULL array twice and populated array the third time. Why is it so? Anyone there to help me sort this issue?

Cart.jsx

import React from "react";
import { Container, Typography, Button, Grid } from "@material-ui/core";

import useStyles from "./CartStyles";

const Cart = ({ cart }) => {
  const classes = useStyles();
  console.log("CART ",cart.line_items); 
  const isEmpty = !cart.line_items.length;

  const EmptyCart = () => {
    <Typography variant="subtitle1">
      You donot have any item in your shopping cart. Start adding some of the
      items in your shopping cart.
    </Typography>;
  };

  const FilledCart = () => {
    <>
      <Grid container spacing={3}>
        {cart.line_items.map((item) => (
          <Grid item xs={12} sm={4} key={item.id}>
            <div>{item.name}</div>
          </Grid>
        ))}
        <div className={classes.cartDetails}>
          <Typography variant="h4">
            Subtotal: {cart.subtotal.formatted_With_symbol}
            <div>
              <Button
                className={classes.emptyButton}
                size="large"
                type="button"
                variant="contained"
                color="secondary"
              >
                Empty Cart
              </Button>
              <Button
                className={classes.checkoutButton}
                size="large"
                type="button"
                variant="contained"
                color="primary"
              >
                Checkout
              </Button>
            </div>
          </Typography>
        </div>
      </Grid>
    </>;
  };

  return (
    <Container>
      <div className={classes.toolbar} />
      <Typography className={classes.title} variant="h3">
        Your Shopping Cart
      </Typography>
      {isEmpty ? <EmptyCart /> : <FilledCart />}
    </Container>
  );
};

export default Cart;

App.js

import React, { useState, useEffect } from "react";
// import Products from "./components/Products/Products";
// import Navbar from "./components/Navbar/Navbar";\
import { commerce } from "./lib/commerce";
import { Products, Navbar, Cart } from './components';

const App = () => {
    const [products, setProducts] = useState([]);
    const [cart, setCart] = useState({});

    const fetchProducts = async() => {
        // call the product api from commerce js
        const { data } = await commerce.products.list();
        // populates the products
        setProducts(data);
    }

    //get element of cart
    const fetchCart = async() => {
        const cartItems = await commerce.cart.retrieve();
        setCart(cartItems);
    }


    const handleAddToCart = async(productId, quantity) => {
        const itemsInCart = await commerce.cart.add(productId, quantity);
        setCart(itemsInCart.cart);
    }

    useEffect(() => {
        //Calling of methods which we want to call on load of component
        fetchProducts();
        fetchCart();
    }, []);
    //  empty array is given so that it makes a call as soon as component is loaded.
    console.log(cart);
    return ( <
        div >
        <
        Navbar totalItems = { cart.total_items }
        / >   <
        Cart cart = { cart }
        /> < /
        div >
    );
};

export default App;

Error Screenshot enter image description here


Solution

  • Issue

    The issue is caused by your initial cart state in App:

    const [cart, setCart] = useState({});
    

    It's an empty object ({}) and passed on to the Cart component that then assumes it has a line_items property.

    const isEmpty = !cart.line_items.length;
    

    Since cart.line_items is undefined an error is thrown when you then attempt to reference the length property.

    Solution

    Use an Optional Chaining operator to guard the null access.

    const isEmpty = !cart.line_items?.length;
    

    Or guard clause/null check

    const isEmpty = !(cart.line_items && cart.line_items.length);
    

    Additional

    Furthermore, I have noticed that the Api returns NULL array twice and populated array the third time. Why is it so? Anyone there to help me sort this issue?

    This is likely a combination of the console.log("CART ",cart.line_items); in the function component body as an unintentional side-effect and the app being rendered into a React.StrictMode component that intentionally double invokes certain functions and component methods twice as a way to help you detect unintentional side-effects.

    Detecting unexpected side effects

    Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

    • Class component constructor, render, and shouldComponentUpdate methods
    • Class component static getDerivedStateFromProps method
    • Function component bodies
    • State updater functions (the first argument to setState)
    • Functions passed to useState, useMemo, or useReducer