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.