Reputation: 141
This should be an easy one. How do I access props.match from within a React component class? Line 17 below contains the culprit.
Edit: I am trying to access the ID parameter from the URL. Edit again to add more relevant code
I don't believe the withRouter
solution is available in the latest version of react-router-dom...
Also, useParams
is not usable in a class component...
post-detail.js, see line 17
5 class Post extends React.Component {
6 constructor(props) {
7 super(props);
8 this.state = {
9 title: '',
10 content: ''
11 };
12 }
13
14 componentDidMount() {
15 let api = new Api();
16
17 api.posts(this.props.match.params.id).then(data => {
18 this.setState({
19 title: data.title.rendered,
20 content: data.content.rendered
21 });
22 });
23 }
24
25 render() {
26 let post = this.state;
27 return (
28 <div className='row'>
29 <h3>{post.title}</h3>
30 <div dangerouslySetInnerHTML={{__html: post.content}} />
31 </div>
32 );
33 }
34 }
35
36 export {Post};
app.js, see line 27
10 class App extends React.Component {
11
12 constructor() {
13 super();
14 this.state = {
15 posts: []
16 };
17 }
18
19 componentDidMount() {}
20
21 render() {
22 return (
23 <div className="container">
24 <h1>hello world</h1>
25 <Routes>
26 <Route exact path='/' element={<PostList />} />
27 <Route path='/post/:id' element={<Post />} />
28 </Routes>
29 </div>
30 );
31 }
32 }
33
34 export default App;
index.js
8 ReactDOM.render(
9 <React.StrictMode>
10 <HashRouter>
11 <App />
12 </HashRouter>
13 </React.StrictMode>,
14 document.getElementById('root')
15 );
Upvotes: 4
Views: 6271
Reputation: 1858
This should be an easy one.
No, not really. Not when you are trying to apply a tool intended for one paradigm to an entirely different paradigm.
From React Router's upgrade guide "Upgrading from v5":
In general, React Router v5.1 (and v6) favors elements over components (or "element types").
And even more so in v6, I assume. The new <Route>
attribute in v6, after all, is called element
(and component
and render
are dead).
Thus, the correct answer has already been given in Muhammad's comment here: React this.props.match is undefined
Or, to reiterate, if you want to continue using class-based components, either (a) use the version of the tool intended for it (thus, v5.x and not v6) or (b) build your own wrapper function in v6 to pass in in the props.
The correct answer for v5.x has already been given by a few others here, which is:
import { withRouter } from 'react-router-dom'
...
export default withRouter(Post)
Looking through my old code that hasn't evolved from class-based components yet, I see I'm currently using three solutions/hacks with React Router v5.2:
The proper withRouter()
solution.
A hack like:
<Route path='/post/:id' render={({match}) => (<Post match={match} /> )} />
React.cloneElement()
as the wrapper function.Itemizing the hack like so: <Route path='/post/:id' render={({match}) => (<Post postId={match.params.id} /> )} />
Keep in mind this was just to lessen the pain on a large-but-low-budget project while upgrading from React Router v2.0 to v5.2. When, really, more refactoring should be done to move all components to elements and do it the new way.
See the v6 FAQ for more details: https://reactrouter.com/docs/en/v6/getting-started/faq
At the top of that FAQ they've written that wrapper function for us (assuming React 16.8+) and conveniently called it withRouter()
:
import {
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
This, I assume, is used just like the v5 withRouter()
.
Upvotes: 1
Reputation: 92
you can modify you code follow below code:
import { withRouter } from "react-router";
export default withRouter(Post)
Upvotes: 0
Reputation: 143
Perhaps, you're using react-router-dom at version 6.
Then, utilize useParams, code is like this.
route:
<Route path="invoices" element={<Invoices />}>
<Route path=":invoiceId" element={<Invoice />} />
</Route>
path=":invoiceId" : thinks url 'http://site/..../invoices/123'
link:
This makes a path navigating.
<Link
style={{ display: "block", margin: "1rem 0" }}
to={`/invoices/${invoice.number}`}
key={invoice.number}
>
{invoice.name}
</Link>
use:
import { useParams } from "react-router-dom";
export default function Invoice() {
let params = useParams();
return <h2>Invoice: {params.invoiceId}</h2>;
}
Please visit here and learn more. https://reactrouter.com/docs/en/v6/getting-started/tutorial#reading-url-params
Be helpful for you, I'm glad too.
Upvotes: 6
Reputation: 66
It looks like you may be using version 6 of react-router-dom
(latest version as of now)
You can use a hook, called useParams()
Checkout below link to get more details
https://reactrouter.com/docs/en/v6/api#useparams
Upvotes: 2
Reputation: 12874
The culprit is at <Route path='/post/:id' element={<Post />} />
Have you tried using component
tag instead? Something like below
<Route path='/post/:id' component={Post} />
Upvotes: 1
Reputation: 601
Please use withRouter.
import { withRouter } from 'react-router-dom'
....
export default withRouter(Post)
Upvotes: 2