There is a routing problem with using react-router-dom v6 to maintain "cart items" functionality in my app. So it doesn't show cart items when I click on the "cart" link in the header navbar. In contrast, it works and displays the list when I try to add a new item to the cart.
Note: It shows the cart items when the URL path is such this pattern 'http://localhost:3000/cart/1?qty=2'
and doesn't show in the case of 'http://localhost:3000/cart'
!
Please follow the code...
App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import HomeScreen from './screens/HomeScreen';
import CartScreen from './screens/CartScreen';
import ProductScreen from './screens/ProductScreen';
function App() {
return (
<>
<Header/>
<Routes>
<Route path="/" element={<HomeScreen />} exact />
<Route path="/product/:id" element={<ProductScreen />} />
<Route path="/cart/:productid?" element={<CartScreen />}/>
</Routes>
);
</>
}
I have configured all the routes, and if you focus on the cart path we add '/cart/' followed by ': productid?' as a product parameter
ProductScreen.js
import { useParams, Link, useNavigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import {Button} from 'react-bootstrap';
function ProductScreen() {
const { id } = useParams(); // the product 'id'
const navigate = useNavigate();
const [qty, setQty] = useState(1); // the product quantity to be added on cart
const dispatch = useDispatch();
const productListDetail = useSelector((state) => state.productDetail);
const { loading, error, product } = productListDetail;
useEffect(() => {
dispatch(listProductDetails(id));
}, [dispatch, id]);
const addToCartHandler = () => {
navigate(`/cart/${id}?qty=${qty}`);
};
return (
<ListGroup>
<ListGroup.Item>
<Row>
<Col> Qty </Col>
<Col xs="auto" className="my-1">
<Form.Control
as="select"
value={qty}
onChange={(e) => setQty(e.target.value)}
>
{[...Array(product.countInStock).keys()]
.map((x) => (
<option key={x + 1} value={x + 1}> {x + 1} </option>
)
)}
</Form.Control>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Button onClick={addToCartHandler} type="button"> Add to Cart </Button>
</ListGroup.Item>
</ListGroup>
)
}
here when you click on 'Add to Cart' button, it will add the item and navigate to the cart list view.
Header.js
import React from 'react';
import { Navbar, Nav, Container } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';
function Header() {
return (
<header >
<Navbar bg="dark" variant="dark" expand="lg" collapseOnSelect>
<Container>
<LinkContainer to="/cart">
<Nav.Link>
<i className="fas fa-shopping-cart"></i>
Cart
</Nav.Link>
</LinkContainer>
</Container>
</Navbar>
</header>
);
}
export default Header;
Here when the user clicks on the 'cart' link, it must navigate to and show all stored items in the cart list, but shows nothing and in the browser's console it warns 'router.ts:11 No routes matched location "/cart/"' message as shown below.
cartScreen.js
import React, { useEffect } from 'react';
import { Col,ListGroup,Row,Image,Button,Card,Form} from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import { useLocation, useNavigate, useParams, Link, Outlet } from 'react-router-dom';
import { addToCart } from '../actions/cartAction';
import Message from '../components/Message';
const CartScreen = () => {
// "useLocation" Returns the current location object, which represents the current URL in web browsers.
const { search } = useLocation();
const { productid } = useParams();
const qty = search ? Number(search.split('=')[1]) : 1;
const dispatch = useDispatch();
const cart = useSelector((state) => state.cart);
const { cartItems } = cart;
useEffect(() => {
dispatch(addToCart(productid, qty));
}, [dispatch, productid, qty]);
return (
<Row>
<Col md={8}>
{cartItems.length === 0 ? (
<Message variant="info">
{' '}
Go Back To Home Page <Link to="/"></Link>
</Message>
) : (
<ListGroup>
{cartItems.map((x) => (
<ListGroup.Item key={x.product}>
{x.name} , {x.qty}
</ListGroup.Item>
))}
</ListGroup>
)}
</Col>
<Col md={4}></Col>
</Row>
);
};
export default CartScreen;