I am building a Django React app following a tutorial where they use react-router v5, and I use the v6.2.1 (code is here : https://github.com/linkedweb/realest_estate/blob/main/src/containers/ListingDetail.js).
I want to have a PrivateRoute for authenticated user rendering details of a product. I tried to adapt the code, according to this post especially (React - TypeError: Cannot read properties of undefined (reading 'params')), but I cannot make it work and I get:
"Uncaught TypeError: Cannot read properties of undefined (reading 'params')"
I tried many variants, but this is what I believe to be the closest to the right way :
App.js
const App = () => (
<Provider store={store}>
<Router>
<Layout >
<Routes>
<Route exact path='/' element={<Home />} />
...
<Route exact path='/listings' element={<Listings/>} />
<Route path='/listings/:id' element={<PrivateRoute />}>
<Route path='' element= {<ListingDetail />}/>
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
</Layout>
</Router>
</Provider>)
PrivateRoute
const PrivateRoute = ({ auth: {isAuthenticated, loading }, ...rest }) => {
return (!isAuthenticated && !loading) ? (<Navigate to='/login' />) : (<Outlet {...rest}/>)}
PrivateRoute.propTypes = {
auth: PropTypes.object.isRequired};
const mapStateToProps = state => ({
auth: state.auth});
export default connect(mapStateToProps)(PrivateRoute);
Listing Details
const ListingDetail = (props) => {
const [listing, setListing] = useState({});
useEffect(() => {
const slug = props.match.params.id;
const config = {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`}};
axios.get(`http://localhost:8000/api/listings/${slug}`, config)
.then(res => {
setListing(res.data);
})
.catch(err => { }); });
return (
<div className='listingdetail'>
<p>{listing.title}</p>
</div>
);};
export default ListingDetail;
I tried to change 'const slug = props.match.params.id;' to 'const { slug } = useParams();', even outside the useEffect, but it didn't work !
What can I do in order to retrieve the data about the product and display them ?
Have a nice day !
CodePudding user response:
Move the path prop to the Route you are trying to render that you want the routed component to access a route param of (slug).
<Route element={<PrivateRoute />}>
<Route
path='/listings/:slug'
element= {<ListingDetail />}
/>
</Route>
ListingDetail should use the useParams hook to retrieve the slug route param. Access the slug route param outside the useEffect hook and add slug to the useEffect hook's dependency array.
const ListingDetail = () => {
const { slug } = usePrams();
const [listing, setListing] = useState({});
useEffect(() => {
const config = {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
},
};
axios.get(`http://localhost:8000/api/listings/${slug}`, config)
.then(res => {
setListing(res.data);
})
.catch(err => { });
}, [slug]);
return (
<div className='listingdetail'>
<p>{listing.title}</p>
</div>
);
};
