I try to nest a route: I have a catalog of products in a Catalog component, which matches with url "backoffice/catalog".
I want to route to Edition component if the url matches with "backoffice/catalog/edit", but I need the Edition component to be a child of Catalog to share props.
I really don't understand why the nested route doesn't work, please save me ! And don't hesitate to tell me if anything is wrong with my App, I know JavaScript well, but I'm starting with React.
Here is my App component:
Here is my Catalog component (the route is made in the render method:
import React from 'react';
import Data from '../../../Utils/Data';
import {Product} from './Product';
import {Edition} from './Edition';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams
} from "react-router-dom";
export class Catalog extends React.Component
{
state = {
title: '',
products: [],
editionProduct: null
};
obtainProducts = () =>
{
Data.products.obtain()
.then(products => {this.setState({products: products});})
};
editProductHandler = product =>
{
this.setState({editionProduct: product});
};
saveProductHandler = product =>
{
Data.products.save(product).then(() => {
this.state.products.map(item => {
item = item._id === product._id ? product : item;
return item;
})
});
};
deleteProductHandler = event =>
{
const productId = event.target.closest('.product-actions').dataset.productid;
let products = this.state.products.filter(product => {
return product._id !== productId;
});
this.setState({products: products}, () => {
Data.products.remove(productId);
});
};
displayProducts = () =>
{
return this.state.products.map(product => {
return (
<li key={product._id} className='catalog-item'>
<Product
deleteProductHandler={this.deleteProductHandler}
editProductHandler={this.editProductHandler}
data={product}
/>
</li>
)
});
};
componentWillMount()
{
this.obtainProducts();
}
render() {
const Products = this.displayProducts();
let { path, url } = useRouteMatch();
return (
<div className={this.state.editionProduct ? 'catalog edit' : 'catalog'}>
<h1>Catalog</h1>
<Switch>
<Route exact path={path}>
<ul className='catalog-list'>{Products}</ul>
</Route>
<Route path={`${path}/edit`}>
<Edition saveProductHandler={this.saveProductHandler} product={this.state.editionProduct} />
</Route>
</Switch>
</div>
);
}
}
Any ideas?
You can't use hooks inside Catalog
component because it is a class component. So you have two ways to resolve your issue:
useRouteMatch
inside Catalog
component. If you need to get match
data inside a component, you need to use withRouter
high-order component.So if you select second way, you will need to wrap your Catalog
component in withRouter
:
export default withRouter(Catalog);
Change one row in render
function from:
let { path, url } = useRouteMatch();
To:
const { path, url } = this.props.match;
And do not forget to change the import of your Catalog
component, because now your component exports as default.