Как вложить маршруты в React Router v4?

Есть ли способ вложить маршруты в React Router v4?

Это работает:

  <Router basename='/app'>
    <main>
      <Route path='/' component={AppBar} />
      <Route path='/customers' component={Customers} />
    </main>
  </Router>

Это не:

  <Router basename='/app'>
    <Route path='/' component={AppBar}>
      <Route path='/customers' component={Customers} />
    </Route>
  </Router>

Компонент клиентов:

import React, { Component, PropTypes } from 'react'
import styled from 'styled-components'

export default class Customers extends Component {
  render () {
    return (
      <Container>
        <h1>Customers</h1>
      </Container>
    )
  }
}

const Container = styled.section`
  height: 100%;
  padding: 15px;
  overflow: auto;
`

5 ответов

Решение

Лучший шаблон, который я нашел до сих пор.

// main app
<div>
    // not setting a path prop, makes this always render
    <Route component={AppShell}/>
    <Switch>
        <Route exact path="/" component={Login}/>
        <Route path="/dashboard" component={AsyncDashboard(userAgent)}/>
        <Route component={NoMatch}/>
    </Switch>
</div>

Я могу просто продолжать вкладывать это внутри компонента, и все работает хорошо, включая hmr(Если вы используете webpack, не забудьте установить output.publicPath в "/")

// dashboard component
<div>
    // the same way as before, not setting a path prop
    // makes it render on every /dashboard/** request 
    <Route component={DashboardTAB}/>
    <Switch>
        // longer path (with same root) than others first
        <Route path="/dashboard/graphs/longerpath" component={GraphForm}/>
        <Route path="/dashboard/graphs" component={Graphs}/>
        <Route path="/dashboard/workers" component={List}/>
        <Route path="/dashboard/insert" component={InsertComponent}/>
    </Switch>
</div>

Я адаптировал это из документации, кажется, работает до сих пор. Вероятно, пропущено что-то очевидное, и да, это не путь v4, но нам нужны все маршруты, определенные в одном месте.

function RouteNest(props){ return (
  <Route exact={props.exact} path={props.path} render={ p => <props.component {...p} children={props.children}/> } />
)}

export const MainRoutes = props => 

<div className='content layout'>

  <Route exact path="/" component={Landing}/>
  <Route  path={'/contact'} component={Contact}/>

  <RouteNest  path={'/thing'} component={CompoWithSub}>
    <RouteNest  path={'/thing/suba'} component={SubComponentA}/>
    <RouteNest  path={'/thing/subb'} component={SubComponentB}/>
  </RouteNest>


</div>

export const CompoWithSub = props => <div>{props.children)</div>

Если кто-то хочет иметь вложенные маршруты без ввода префикса маршрута оболочки, я создал что-то вроде этого в TSX:

Импорт:

import * as React from 'react';
import { Route, RouteComponentProps, RouteProps, Switch } from 'react-router-dom';
import Index from 'views/index';
import Login from 'views/login';
import NoMatch from 'views/no-match';

Интерфейсы:

interface INestedRoutes {
    nested?: string;
}

interface INestedRoute extends RouteProps, INestedRoutes {}

Оболочка NestedRoute и NestedRoutes:

class NestedRoutes extends React.Component<INestedRoutes> {
    public render() {
        const childrenWithProps = React.Children.map(this.props.children, (child) => {
            return React.cloneElement(
                child as React.ReactElement<any>, { nested: this.props.nested },
            );
        })
        return childrenWithProps;
    }
}


const NestedRoute: React.SFC<INestedRoute> = (props: INestedRoute) => {
    return <Route path={`${props.nested}${props.path}`} component={props.component} />;
};

И маршруты с оберткой:

const MultiLanguage: React.SFC<RouteComponentProps<any>> = (props: RouteComponentProps<any>) => {
    return (
        <NestedRoutes nested={props.match.path} >
            <NestedRoute path="/test" component={Login} />
            <NestedRoute path="/no-match" component={NoMatch} />
        </NestedRoutes>
    );
};


export default (
    <Switch>
        <Route path="/:language" component={MultiLanguage}/>
        <Route exact={true} path="/" component={Index} />
        <Route path="/login" component={Login} />
        <Route component={NoMatch} />
    </Switch>
);

Вы компонент AppBar отвечает за визуализацию клиентов. Чтобы клиенты вызывались, вы должны отобразить дочерние элементы AppBar. Все, что непосредственно вложено в AppBar, является дочерним для AppBar.

import React from 'react';

const AppBar = ({ children }) => (
  <div>
    <header>
       <h1> stuff </h1>
    </header>
    {children}
  </div>
);

export default AppBar

Обратите внимание, что при посещении "/" будет отображаться только AppBar. AppBar и клиенты будут отображаться при посещении "/ клиентов".

Для вложенных маршрутов есть очень простой способ, который я использую.

Пример основного роутера будет таким

<Router history={history}>
  <Switch >
    <Route path="/" component={Home}></Route>
  </Switch>
</Router>

Компонент Inside Home с использованием Nested Routing выглядит так:

<div className="App">
  <Navbar title="Home" links = { NavbarLinks }/>
  {this.renderContentPage()}
</div>

renderContentPage проверит URL-адрес и отобразит вложенный маршрут.

<Route exact path="/" component={Page1}></Route>
<Route exact path="/page1" component={Page1}></Route>
<Route exact path='/page2' component={Page2} />

Итак, внутри компонента Home компоненты page1 и page2 отображаются.

Маршрут ожидает одного дочернего элемента, то есть компонента. Это не должен быть новый Рут. Что вы можете сделать, так это включить вложенные маршруты в компонент клиентов.

Также не забудьте удалить внутри маршрутов в компоненте клиентов.

Другие вопросы по тегам