'How to pass params into link using React router v6?
This is my main section class where all routes to the links is kept
export default class Section extends React.Component {
render() {
return (
<div style={{backgroundColor:"white"}}>
<Routes>
<Route path="/" element={<Home/>} />
<Route path="/discover" element={<Discover/>} />
<Route path="/shop/makeup" element={<Makeup/>} />
<Route path="/home/:id" element={<DetailsPage/>} />
</Routes>
</div>
)}}
This is my card page which is getting data from the context.
import React from 'react';
import {DataContext} from './CardData.js';
import {Link} from 'react-router-dom'
import '../App.css';
export default class HomeCard extends React.Component {
static contextType = DataContext;
render(){
const {products} = this.context;
return (
<div>
<div className="card">
{ products.map((val,index)=>{
return(
<div className="card" key={val.id}>
<Card style={{ width: '14rem' }} className="cardhead">
<Card.Img variant="top" src={val.imgsrc} className="cardimg"/>
<Card.Body>
<Card.Text>{val.mname}
</Card.Text>
<Card
From here i had passed the val.id to the url of the page using LINK
<Link to={`/home/${val.id}`}>
<Button className="overlay" variant="primary">
{/* <a style={{color:"white"}} href={props.link} className="card-link">View</a> */}
View</Button> </Link>
<Card.Text><strong>{val.price}</strong>
</Card.Text>
<Card.Text><strong>{val.id}</strong>
</Card.Text>
</Card.Footer>
</Card.Body>
</Card>
</div>);
</div>
)}}
I want to access the the link url into the details page of my product which is as follows :
export default class DetailsPage extends React.Component {
static contextType = DataContext;
state = {
product: []
}
getProduct = () =>{
if(this.props.match.params.id){
const res = this.context.products;
const data = res.filter(item =>{
return item.id === this.props.match.params.id
})
this.setState({product: data})
}};
componentDidMount(){
this.getProduct();
}
render() {
const {product} = this.state;
const {addCart} = this.context;
return (
<>
{product.map(item =>(
<div className="details" key={item.id}>
<img src={item.imgsrc} alt=""/>
<div className="box">
<div className="row">
<h2>{item.mname}</h2>
<span>${item.price}</span>
</div>
<Link to="/cart" className="cart" onClick={() => addCart(item.id)}>
Add to cart
</Link>
</div> </div> ))} </> ) }}
Unfortunately it is giving an error saying TypeError: Cannot read property 'params' of undefined
Solution 1:[1]
Navigate programmatically
Send parameters to useNavigate
const navigate = useNavigate();
function _navigateToPage (pageNumber) {
const page = pageNumber
const title = "Hello World";
navigate("/fragment", {
state:{
page,
title
},
});
}
Retrieve parameters in other page with useLocation
const params = useLocation();
console.log(params);
Solution 2:[2]
Issue(s)
- react-router-dom v6
Routecomponents rendered via theelementprop don't receive route props. - Route children components must use react hooks to access the route context, i.e.
useParams,useLocation,useNavigate, etc... and therefore must be function components. - There no longer exists a
withRouterHigher Order Component.
Solution
DetailsPage is a class-based component so I see a couple options for getting access to the route's match params.
- Convert
DetailsPageto be a function component and use theuseParamsreact hook. - Write your own
withRouterHOC to access the route context and pass as props any of the react-hook accessible values.
I won't cover converting a class-based component to a function component, but can provide a simple HOC solution to pass to DetailsPage (or any other class-based component) the match params.
const withRouter = WrappedComponent => props => {
const params = useParams();
// etc... other react-router-dom v6 hooks
return (
<WrappedComponent
{...props}
params={params}
// etc...
/>
);
};
You can now wrap & export your class-based components in the very familiar way they were from v4/v5.
Solution 3:[3]
Using react-router-dom v6
Parent component (App)
<Route path="/something/:id" element={<Something />} />
Child component (Something)
import { useParams } from "react-router-dom";
const Something = (props) => {
let { id } = useParams();
useEffect(() => {
console.log(`/something/${id}`);
}, []);
// .....
}
Solution 4:[4]
Pass props via Link component in React Router v6 by a separate prop called state like <Link to="/" state={{ foo: bar }}>.
Example:
<Link
to={`/login`}
state={{ from: "the-page-id" }}
>
Login to see this page
</Link>
And retrieve it using useLocation() hook:
import { useLocation } from "react-router-dom";
...
const location = useLocation();
const { from } = location.state;
console.log(from); // output: "the-page-id"
This should be used with function components only not class components.
Solution 5:[5]
I had this same problem and scoured the internet for an easy solution. I didn't want to rewrite all my class components as functional components but I thought I might have to. However, I used a withRouter function with useParams() and it works really well and is easy to follow.
To solve your problem so you don't have to rewrite your DetailsPage class as a function, follow these steps:
Add the following line of code at the beginning of your class:
import { useParams } from 'react-router-dom';Then add this function above your class (copy it exactly):
export function withRouter(Children){ return(props)=>{ const match = {params: useParams()}; return <Children {...props} match = {match}/> } }Next, change your class definition to this:
class DetailsPage extends React.Component {Add the following line of code at the end of your class:
export default withRouter(DetailsPage);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Aindriú |
| Solution 2 | |
| Solution 3 | jasonleonhard |
| Solution 4 | |
| Solution 5 | Gina Cooper |
