Home > Software engineering >  Why react-router-dom send the following message: No routes matched location "/shopping-cart&quo
Why react-router-dom send the following message: No routes matched location "/shopping-cart&quo

Time:07-25

I am new to react-router-dom v6 and trying to route a new page when clicking on a button. But the link I have created normally have some params and I do not how to fix the route.

In App.js I have the following:

import React from 'react';
import { Container } from 'react-bootstrap';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import HomeScreen from './screens/HomeScreen';
import ProductScreen from './screens/ProductScreen';
import ShoppingCartScreen from './screens/ShoppingCartScreen';

const App = () => {
  return (
    <Router>
      <Container>
        <Routes>
          <Route path='/' element={<HomeScreen />} exact />
          <Route path='/product/:id' element={<ProductScreen />} />
          <Route path='shopping-cart/:id?' element={<ShoppingCartScreen />} />
        </Routes>
      </Container>
    </Router>
  );
}

export default App;

I create the <Route path='shopping-cart/:id?' element={<ShoppingCartScreen />} /> for the navigation in App.js and in the product screen I create an Add to cart button to go to the ShoppingCartScreen like so:

import React, { useState, useEffect } from 'react';
import { Link, useParams, useNavigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux'
import { Button } from 'react-bootstrap';

const ProductScreen = () => {
  const [quantity, setQuantity] = useState(1)
  let params = useParams();
  let navigate = useNavigate()

  const addToCardHandler = () => {
    navigate(`/shopping-cart/${params.id}?quantity=${quantity}`)
  }

  return (
    <div>
      <Button 
        className='btn-success'
        type='button'
        onClick={addToCardHandler}
      > 
        Add to Cart 
      </Button>
    </div>
  )
}

I also have a navigation component (Header) and I use react-bootstrap to create it:

import React from 'react';
import {Container, Navbar, Nav } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';

const Header = () => {
  return (
    <header>
      <Navbar expand='lg' variant='dark' bg='primary' collapseOnSelect>
        <Container>
          <LinkContainer to="/">
            <Navbar.Brand>Azakamede</Navbar.Brand>
          </LinkContainer>
          <Navbar.Toggle aria-controls="navbarScroll" />
          <Navbar.Collapse id="navbarScroll">
            <Nav
              className="me-auto my-2 my-lg-0"
              style={{ maxHeight: '100px' }}
              navbarScroll
            >
              <LinkContainer to="/">
                <Nav.Link><i className="fas fa-house"></i>Products</Nav.Link>
              </LinkContainer>
              <LinkContainer to="/shopping-cart">
                <Nav.Link ><i className='fas fa-shopping-cart'></i>Cart</Nav.Link>
              </LinkContainer>
              <LinkContainer to="/login">
                <Nav.Link ><i className="fas fa-user"></i>Login</Nav.Link>
              </LinkContainer>
            </Nav>
          </Navbar.Collapse>
        </Container>
      </Navbar> 
    </header>
  );
}

export default Header

Finally I have my Shopping cart screen:

import React from 'react'

const ShoppingCartScreen = () => {
  return (
    <div>
      <h1> My Cart </h1>
    </div>
  )
}

export default ShoppingCartScreen

I think that the problem is in the addToCardHandler but don't know how to fix it.

Note that in react-router-dom v5 I will have something like the following:

const addToCardHandler = () => {
  history.push(`/shopping-cart/${params.id}?quantity=${quantity}`)
}

CodePudding user response:

The code is missing a route matching "/shopping-cart". react-router-dom@6 Route components don't take paths with optional parameters. If you need to render a component on "/shopping-cart" and /shopping-cart/:id" then you need a route for each.

Example:

<Router>
  <Container>
    <Routes>
      <Route path='/' element={<HomeScreen />} />
      <Route path='/product/:id' element={<ProductScreen />} />
      <Route path='shopping-cart' element={<ShoppingCartScreen />} />
      <Route path='shopping-cart/:id' element={<ShoppingCartScreen />} />
    </Routes>
  </Container>
</Router>

or using nested routing

<Router>
  <Container>
    <Routes>
      <Route path='/' element={<HomeScreen />} />
      <Route path='/product/:id' element={<ProductScreen />} />
      <Route path='shopping-cart'>
        <Route index element={<ShoppingCartScreen />} />
        <Route path=':id' element={<ShoppingCartScreen />} />
      </Route>
    </Routes>
  </Container>
</Router>

CodePudding user response:

React Router v6 changed how optional parameters are defined in Routes. Here is a thread on their github repo discussing the change: https://github.com/remix-run/react-router/issues/7285

To achieve what you're attempting to do, your Routes will need to look like this:

<Routes>
  <Route path='/' element={<HomeScreen />} exact />
  <Route path='/product/:id' element={<ProductScreen />} />
  <Route path='/shopping-cart/'>
    <Route path=':id?' element={<ShoppingCartScreen />} />
    <Route path='' element={<ShoppingCartScreen />} />
  </Route>
</Routes>;

And then in your <ShoppingCartScreen /> component you will need to handle the case where id is not provided.

  • Related