wake-up-neo.net

Verschachtelte Routen mit Reakt-Router v4

Ich kämpfe derzeit mit Schachtelrouten mit dem reakt Router v4.

Das nächste Beispiel war die Routenkonfiguration in der React-Router v4-Dokumentation .

Ich möchte meine App in zwei Teile teilen.

Ein Frontend und ein Admin-Bereich.

Ich habe über so etwas nachgedacht:

<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} />

Das Frontend hat ein anderes Layout und einen anderen Stil als der Admin-Bereich. Also innerhalb der Frontpage die Route nach Hause, über und so sollte man die Kinderrouten sein.

/ home sollte in die Frontpage-Komponente gerendert werden und / admin/home sollte in der Backend-Komponente dargestellt werden. 

Ich habe einige Variationen ausprobiert, endete aber damit, dass ich/home oder/admin/home nicht traf.

Bearbeiten - 19.04.2017

Da dieser Beitrag momentan viele Ansichten hat, habe ich ihn mit der endgültigen Lösung aktualisiert. Ich hoffe es hilft jemandem.

Bearbeiten - 08.05.2017

Alte Lösungen entfernt

Endgültige Lösung:

Dies ist die endgültige Lösung, die ich gerade verwende. Dieses Beispiel hat auch eine globale Fehlerkomponente wie eine herkömmliche 404-Seite.

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;
185
datoml

In Reaktiver-Router-v4 verschachteln Sie nicht <Routes />. Stattdessen legen Sie sie in einen anderen <Component />.


Zum Beispiel

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

soll werden

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

mit

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

Hier ist ein einfaches Beispiel direkt vom Reakt-Router Dokumentation .

227
Lyubomir

Ich wollte nur erwähnen, dass der Reakt-Router v4 radikal geändert wurde, da diese Frage veröffentlicht/beantwortet wurde.

Es gibt keine <Match>-Komponente mehr! <Switch>ist sicherzustellen, dass nur die erste Übereinstimmung gerendert wird. <Redirect> gut .. leitet auf eine andere Route um. Verwenden oder exact weglassen, um eine partielle Übereinstimmung entweder ein- oder auszuschließen.

Siehe die Dokumente. Sie sind großartig. https://reacttraining.com/react-router/

Hier ist ein Beispiel, von dem ich hoffe, dass es nützlich ist, um Ihre Frage zu beantworten.

  <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>

Hoffe es hat geholfen, lass es mich wissen. Wenn dieses Beispiel Ihre Frage nicht gut genug beantwortet, sagen Sie es mir und ich werde sehen, ob ich sie ändern kann.

40
jar0m1r

Um Routen zu verschachteln, müssen Sie sie in der untergeordneten Komponente der Route platzieren. 

Wenn Sie jedoch eher eine "Inline" -Syntax bevorzugen, als Ihre Routen in mehrere Komponenten aufzuteilen, können Sie die render -Eigenschaft für den <Route> verwenden, unter dem Sie verschachteln möchten, und zwar mit einer inline-statusfreien Funktionskomponente.

<BrowserRouter>

  <Route exact path="/" component={Frontpage} />
  <Route path="/home" component={HomePage} />
  <Route path="/about" component={AboutPage} />

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

</BrowserRouter>

Wenn Sie daran interessiert sind, warum render anstelle von component verwendet werden sollte, verhindern Sie, dass die Inline-Komponente bei jedem Rendern erneut gemountet wird. Weitere Informationen finden Sie in der Dokumentation .

Beachten Sie auch, dass das obige Beispiel React 16 Fragments verwendet, um die verschachtelten Routen einzuwickeln, um sie etwas sauberer zu machen. Vor React 16 können Sie stattdessen einfach einen Container <div> verwenden.

30
davnicwil

Etwas wie das.

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;

4
Sanjeev Shakya

Sie können etwas wie Routes.js versuchen

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;

Ich denke, man kann das auch von hier aus erreichen.

1

Es ist mir gelungen, verschachtelte Routen durch Umbrechen mit Switch zu definieren und die verschachtelte Route vor der Stammroute zu definieren.

<BrowserRouter>
  <Switch>
    <Route path="/staffs/:id/edit" component={StaffEdit} />
    <Route path="/staffs/:id" component={StaffShow} />
    <Route path="/staffs" component={StaffIndex} />
  </Switch>
</BrowserRouter>

Referenz: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md

0
asukiaaa

Hier habe ich ein Beispiel in TSX erstellt, wenn jemand das Präfix der Wrapper-Route im Pfad der untergeordneten Route entfernen möchte: https://stackoverflow.com/a/47891060/5517306

0
Marcin Sadowski