J'essaie d'imbriquer une route: j'ai un catalogue de produits dans un composant Catalogue, qui correspond à l'url "backoffice/catalogue" .
Je veux router vers Edition composant si l'url correspond à "backoffice/catalogue/edit" , mais j'ai besoin du - Edition composant pour être un enfant de Catalogue pour partager les accessoires.
Je ne comprends vraiment pas pourquoi la route imbriquée ne fonctionne pas, veuillez me sauver! Et n'hésitez pas à me dire si quelque chose ne va pas avec mon application, je connais bien Javascript, mais je commence par React: D
Voici mon composant d'application:
import React from "react";
import { Route, Switch } from "react-router-dom";
import { Home } from "./components/Static/Home.js";
import { Dashboard } from "./components/Backoffice/Dashboard.js";
import { Catalog } from "./components/Backoffice/catalog/Catalog.js";
import { Login } from "./components/Login/Login.js";
import { Signup } from "./components/Signup/Signup.js";
import { PrivateRoute } from "./components/PrivateRoute.js";
import "./scss/App.scss";
import {Header} from "./components/Structure/Header";
import {BOHeader} from "./components/Structure/Backoffice/Header";
import {List} from "./components/Listing/List";
function App()
{
return (
<div className="App">
<div className="App-content">
<Switch>
<Route path='/backoffice' component={BOHeader} />
<Route path='/' component={Header} />
</Switch>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/login' component={Login} />
<Route exact path='/signup' component={Signup} />
<Route path='/listing' component={List}/>
<PrivateRoute exact path='/backoffice' component={Dashboard}/>
<PrivateRoute exact path='/backoffice/catalog' component={Catalog}/>
</Switch>
</div>
</div>
);
}
export default App;
Voici mon composant Catalogue (l'itinéraire est fait dans la méthode de rendu:
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>
);
}
}
Des idées ?
Comme j'ai eu le même problème lors de la configuration de mon React routeur avec TypeScript, je vais détailler un peu plus la réponse d'Andrii en 4 étapes:
yarn add react-router-dom --save
yarn add @types/react-router-dom --save-dev
ou
npm install react-router-dom --save
npm install @types/react-router-dom --save-dev
1) Lors de l'importation de votre composant d'ordre supérieur (application dans le cas présent), n'utilisez pas de crochets car l'application sera exportée par défaut;
2) BrowserRouter doit être à un niveau supérieur plutôt que la classe qui sera exportée en tant que "par défaut withRouter (Class)", afin d'éviter l'erreur suivante:
"Vous ne devez pas utiliser Route ou withRouter () en dehors d'un routeur"
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import * as serviceWorker from './serviceWorker';
import App from './app';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
serviceWorker.unregister();
1) Importer depuis react-router-dom, withRouter & RouteComponentProps (ou votre propre définition PropType);
2) Étendez React.Component et utilisez l'interface RouteComponentProps;
3) Passez les accessoires aux composants que vous souhaitez partager les données de routage;
4) Exportez la classe d'ordre supérieur sous la forme par défaut avec Routeur.
import React, { ReactElement } from 'react';
import { Switch, Route, withRouter, RouteComponentProps } from 'react-router-dom';
import { ExpensesPage } from './pages/expenses/expenses.page';
import { HomePage } from './pages/home/home.page';
import { HeaderComponent } from './components/header/header.component';
import './app.scss';
class App extends React.Component<RouteComponentProps> {
public render(): ReactElement {
return (
<div className='playground'>
<HeaderComponent {...this.props} />
<div className="playground-content">
<Switch>
<Route exact path='/' component={HomePage} {...this.props} />
<Route exact path='/expenses' component={ExpensesPage} {...this.props} />
</Switch>
</div>
</div>
);
}
}
export default withRouter(App);
Grâce à votre RouteComponentProps étendant votre classe, vous pouvez accéder normalement aux accessoires de routage comme historique, emplacement et correspondance comme ci-dessous:
import React, { ReactElement } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import './header.component.scss';
export class HeaderComponent extends React.Component<RouteComponentProps> {
public render(): ReactElement {
const { location } = this.props;
console.log(location.pathname);
return (
<header className="header">
{/* ... */}
</header >
);
}
}
J'espère que cela aide, car j'ai eu un peu de difficulté à faire fonctionner cela dans un environnement simple avec webpack et sans redux. Dernière utilisation correcte avec les versions suivantes:
{
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2",
"sass-loader": "^8.0.2",
"style-loader": "^1.1.3",
"TypeScript": "^3.8.2",
"webpack": "^4.41.6",
"webpack-dev-server": "^3.10.3",
},
{
"@types/react-router-dom": "^5.1.3",
"webpack-cli": "^3.3.11"
}