subroutes react javascript reactjs nested react-router react-router-v4

javascript - subroutes - static router react router dom



Rutas anidadas con react router v4/v5 (7)

Algo como esto.

import React from ''react''; import { BrowserRouter as Router, Route, NavLink, Switch, Link } from ''react-router-dom''; import ''../assets/styles/App.css''; const Home = () => <NormalNavLinks> <h1>HOME</h1> </NormalNavLinks>; const About = () => <NormalNavLinks> <h1>About</h1> </NormalNavLinks>; const Help = () => <NormalNavLinks> <h1>Help</h1> </NormalNavLinks>; const AdminHome = () => <AdminNavLinks> <h1>root</h1> </AdminNavLinks>; const AdminAbout = () => <AdminNavLinks> <h1>Admin about</h1> </AdminNavLinks>; const AdminHelp = () => <AdminNavLinks> <h1>Admin Help</h1> </AdminNavLinks>; const AdminNavLinks = (props) => ( <div> <h2>Admin Menu</h2> <NavLink exact to="/admin">Admin Home</NavLink> <NavLink to="/admin/help">Admin Help</NavLink> <NavLink to="/admin/about">Admin About</NavLink> <Link to="/">Home</Link> {props.children} </div> ); const NormalNavLinks = (props) => ( <div> <h2>Normal Menu</h2> <NavLink exact to="/">Home</NavLink> <NavLink to="/help">Help</NavLink> <NavLink to="/about">About</NavLink> <Link to="/admin">Admin</Link> {props.children} </div> ); const App = () => ( <Router> <div> <Switch> <Route exact path="/" component={Home}/> <Route path="/help" component={Help}/> <Route path="/about" component={About}/> <Route exact path="/admin" component={AdminHome}/> <Route path="/admin/help" component={AdminHelp}/> <Route path="/admin/about" component={AdminAbout}/> </Switch> </div> </Router> ); export default App;

Actualmente estoy luchando con las rutas de anidamiento usando react router v4.

El ejemplo más cercano fue la configuración de ruta en la documentación de React-Router v4 .

Quiero dividir mi aplicación en 2 partes diferentes.

Una interfaz y un área de administración.

Estaba pensando en algo como esto:

<Match pattern="/" component={Frontpage}> <Match pattern="/home" component={HomePage} /> <Match pattern="/about" component={AboutPage} /> </Match> <Match pattern="/admin" component={Backend}> <Match pattern="/home" component={Dashboard} /> <Match pattern="/users" component={UserPage} /> </Match> <Miss component={NotFoundPage} />

La interfaz tiene un diseño y un estilo diferentes que el área de administración. Entonces, dentro de la portada, la ruta a casa, aproximadamente, y así deberían ser las rutas secundarias.

/ home debería representarse en el componente Frontpage y / admin / home debería representarse en el componente Backend.

Intenté algunas variaciones, pero siempre terminaba sin golpear / home o / admin / home.

Editar - 19.04.2017

Debido a que esta publicación tiene muchas vistas en este momento, la actualicé con la solución final. Espero que esto ayude a alguien.

Editar - 08.05.2017

Se eliminaron las soluciones antiguas.

Solución final:

Esta es la solución final que estoy usando en este momento. Este ejemplo también tiene un componente de error global como una página 404 tradicional.

import React, { Component } from ''react''; import { Switch, Route, Redirect, Link } from ''react-router-dom''; const Home = () => <div><h1>Home</h1></div>; const User = () => <div><h1>User</h1></div>; const Error = () => <div><h1>Error</h1></div> const Frontend = props => { console.log(''Frontend''); return ( <div> <h2>Frontend</h2> <p><Link to="/">Root</Link></p> <p><Link to="/user">User</Link></p> <p><Link to="/admin">Backend</Link></p> <p><Link to="/the-route-is-swiggity-swoute">Swiggity swooty</Link></p> <Switch> <Route exact path=''/'' component={Home}/> <Route path=''/user'' component={User}/> <Redirect to={{ state: { error: true } }} /> </Switch> <footer>Bottom</footer> </div> ); } const Backend = props => { console.log(''Backend''); return ( <div> <h2>Backend</h2> <p><Link to="/admin">Root</Link></p> <p><Link to="/admin/user">User</Link></p> <p><Link to="/">Frontend</Link></p> <p><Link to="/admin/the-route-is-swiggity-swoute">Swiggity swooty</Link></p> <Switch> <Route exact path=''/admin'' component={Home}/> <Route path=''/admin/user'' component={User}/> <Redirect to={{ state: { error: true } }} /> </Switch> <footer>Bottom</footer> </div> ); } class GlobalErrorSwitch extends Component { previousLocation = this.props.location componentWillUpdate(nextProps) { const { location } = this.props; if (nextProps.history.action !== ''POP'' && (!location.state || !location.state.error)) { this.previousLocation = this.props.location }; } render() { const { location } = this.props; const isError = !!( location.state && location.state.error && this.previousLocation !== location // not initial render ) return ( <div> { isError ? <Route component={Error} /> : <Switch location={isError ? this.previousLocation : location}> <Route path="/admin" component={Backend} /> <Route path="/" component={Frontend} /> </Switch>} </div> ) } } class App extends Component { render() { return <Route component={GlobalErrorSwitch} /> } } export default App;


Aquí he creado un ejemplo en TSX, si alguien quiere deshacerse del prefijo de la ruta del contenedor en la ruta de la ruta secundaria: https://.com/a/47891060/5517306


Es cierto que para anidar rutas, debe colocarlas en el componente secundario de la ruta.

Sin embargo, si prefiere una sintaxis más en línea en lugar de dividir sus Rutas entre los componentes, puede proporcionar un componente funcional al accesorio de render de la Ruta en la que desea anidar.

<BrowserRouter> <Route path="/" component={Frontpage} exact /> <Route path="/home" component={HomePage} /> <Route path="/about" component={AboutPage} /> <Route path="/admin" render={({ match: { url } }) => ( <> <Route path={`${url}/`} component={Backend} exact /> <Route path={`${url}/home`} component={Dashboard} /> <Route path={`${url}/users`} component={UserPage} /> </> )} /> </BrowserRouter>

Si está interesado en saber por qué se debe usar el accesorio de render , y no el accesorio del component , es porque impide que el componente funcional en línea se vuelva a montar en cada render. Vea la documentación para más detalles.

Tenga en cuenta que el ejemplo envuelve las Rutas anidadas en un Fragment . Antes de React 16, puede usar un contenedor <div> lugar.


Puedes probar algo como Routes.js

import React, { Component } from ''react'' import { BrowserRouter as Router, Route } from ''react-router-dom''; import FrontPage from ''./FrontPage''; import Dashboard from ''./Dashboard''; import AboutPage from ''./AboutPage''; import Backend from ''./Backend''; import Homepage from ''./Homepage''; import UserPage from ''./UserPage''; class Routes extends Component { render() { return ( <div> <Route exact path="/" component={FrontPage} /> <Route exact path="/home" component={Homepage} /> <Route exact path="/about" component={AboutPage} /> <Route exact path="/admin" component={Backend} /> <Route exact path="/admin/home" component={Dashboard} /> <Route exact path="/users" component={UserPage} /> </div> ) } } export default Routes

App.js

import React, { Component } from ''react''; import logo from ''./logo.svg''; import ''./App.css''; import { BrowserRouter as Router, Route } from ''react-router-dom'' import Routes from ''./Routes''; class App extends Component { render() { return ( <div className="App"> <Router> <Routes/> </Router> </div> ); } } export default App;

Creo que puedes lograr lo mismo desde aquí también.


Solo quería mencionar que react-router v4 cambió radicalmente desde que esta pregunta fue publicada / respondida.

¡Ya no hay un componente <Match> ! <Switch> es para asegurarse de que solo se muestre la primera coincidencia. <Redirect> bueno ... redirige a otra ruta. Use o omita exact para incluir o excluir una coincidencia parcial.

Ver los documentos. Son geniales. https://reacttraining.com/react-router/

Aquí hay un ejemplo que espero sea útil para responder a su pregunta.

<Router> <div> <Redirect exact from=''/'' to=''/front''/> <Route path="/" render={() => { return ( <div> <h2>Home menu</h2> <Link to="/front">front</Link> <Link to="/back">back</Link> </div> ); }} /> <Route path="/front" render={() => { return ( <div> <h2>front menu</h2> <Link to="/front/help">help</Link> <Link to="/front/about">about</Link> </div> ); }} /> <Route exact path="/front/help" render={() => { return <h2>front help</h2>; }} /> <Route exact path="/front/about" render={() => { return <h2>front about</h2>; }} /> <Route path="/back" render={() => { return ( <div> <h2>back menu</h2> <Link to="/back/help">help</Link> <Link to="/back/about">about</Link> </div> ); }} /> <Route exact path="/back/help" render={() => { return <h2>back help</h2>; }} /> <Route exact path="/back/about" render={() => { return <h2>back about</h2>; }} /> </div>

Espero que haya ayudado, hágamelo saber. Si este ejemplo no responde su pregunta lo suficientemente bien, dígame y veré si puedo modificarlo.


En react-router-v4 no anidas <Routes /> . En cambio, los pones dentro de otro <Component /> .

Por ejemplo

<Route path=''/topics'' component={Topics}> <Route path=''/topics/:topicId'' component={Topic} /> </Route>

debe convertirse

<Route path=''/topics'' component={Topics} />

con

const Topics = ({ match }) => ( <div> <h2>Topics</h2> <Link to={`${match.url}/exampleTopicId`}> Example topic </Link> <Route path={`${match.url}/:topicId`} component={Topic}/> </div> )

Aquí hay un ejemplo básico directamente de la documentation react-router.


interface IDefaultLayoutProps { children: React.ReactNode } const DefaultLayout: React.SFC<IDefaultLayoutProps> = ({children}) => { return ( <div className="DefaultLayout"> {children} </div> ); } const LayoutRoute: React.SFC<IDefaultLayoutRouteProps & RouteProps> = ({component: Component, layout: Layout, ...rest}) => { const handleRender = (matchProps: RouteComponentProps<{}, StaticContext>) => ( <Layout> <Component {...matchProps} /> </Layout> ); return ( <Route {...rest} render={handleRender}/> ); } const ScreenRouter = () => ( <BrowserRouter> <div> <Link to="/">Home</Link> <Link to="/counter">Counter</Link> <Switch> <LayoutRoute path="/" exact={true} layout={DefaultLayout} component={HomeScreen} /> <LayoutRoute path="/counter" layout={DashboardLayout} component={CounterScreen} /> </Switch> </div> </BrowserRouter> );