React Router v4具有多种布局

Flo*_*elt 35 reactjs react-router

我想在我的公共布局中渲染我的一些路线,以及我的私人布局中的其他一些路线,是否有一个干净的方法来做到这一点?

示例显然不起作用,但我希望大致解释我正在寻找的内容:

<Router>

  <PublicLayout>
    <Switch>
      <Route exact path="/" component={HomePage} />
      <Route exact path="/about" component={AboutPage} />
    </Switch>
  </PublicLayout>

  <PrivateLayout>
    <Switch>
      <Route exact path="/profile" component={ProfilePage} />
      <Route exact path="/dashboard" component={DashboardPage} />
    </Switch>
  </PrivateLayout>

</Router>
Run Code Online (Sandbox Code Playgroud)

我想要切换某些路由的布局,如何使用新的路由器做到这一点?

嵌套路由不再有效,并给我这个错误:

You should not use <Route component> and <Route children> in the same route; <Route children> will be ignored
Run Code Online (Sandbox Code Playgroud)

编辑:布局包装整个路径组也意味着只要您保留在同一个私有/公共路由组中,这些布局只会呈现一次.如果您的布局必须从您的服务器获取某些内容,这是一个大问题,因为如果您使用布局包装每个页面,那么每次更改都会发生这种情况.

Zap*_*ree 28

我为此做的是创建一个简单的组件,为Route组件添加一个额外的属性,即布局:

function RouteWithLayout({layout, component, ...rest}){
  return (
    <Route {...rest} render={(props) =>
      React.createElement( layout, props, React.createElement(component, props))
    }/>
  );
}
Run Code Online (Sandbox Code Playgroud)

那么在您的情况下,您的路线将如下所示

<Switch>
    <RouteWithLayout layout={PublicLayout} path="/" component={HomePage}/>
    <RouteWithLayout layout={PublicLayout} path="/about" component={AboutPage}/>
    <RouteWithLayout layout={PrivateLayout} path="/profile" component={ProfilePage}/>
    <RouteWithLayout layout={PrivateLayout} path="/dashboard" component={DashboardPage}/>
</Switch>
Run Code Online (Sandbox Code Playgroud)

  • 这里最大的不便之处是您的布局会针对您访问的每条路线进行重新渲染。如果您的`Switch`嵌套在版面内,则性能会更好。 (3认同)

Seb*_*rin 15

2019+

找到后,干净有效的方式(避免滥用重新渲染):

    <Route exact path={["/about", "/"]}>
      <PublicLayout>
        <Route exact path="/" component={HomePage} />
        <Route path="/about" component={AboutPage} />
      </PublicLayout>
    </Route>
    <Route path={["/profile", "/dashboard"]}>
      <PrivateLayout>
        <Route path="/profile" component={ProfilePage} />
        <Route path="/dashboard" component={DashboardPage} />
      </PrivateLayout>
    </Route>
Run Code Online (Sandbox Code Playgroud)

同样,它可以重构,请参阅我的完整答案:https : //stackoverflow.com/a/57358661/3437790


Dav*_*eña 7

如果你正在使用Typescript并希望遵循这个反应布局方法,那么你可以像这样声明你的布局:

import './Default.less';

import React from 'react';
import { Route } from "react-router-dom";

import { Sider } from './Components';
import { Notification } from 'Client/Components';

interface IDefaultProps {
  component: any
  path?: string;
  exact?: boolean;
}

const Default: React.SFC<IDefaultProps> = (props) => {
  const { component: Component, ...rest } = props;
  return <Route {...rest} render={matchProps => (
    <div className="defaultLayout">
      <Sider />
      <div className="defaultLayoutContent">
        <Component {...matchProps} />
      </div>
      <Notification />
    </div>
  )} />
}

export default Default;
Run Code Online (Sandbox Code Playgroud)

并声明这样的路线:

import React from 'react';
import { Route } from 'react-router-dom';

import { DefaultLayout } from 'Client/Layout';
import { Dashboard, Matters, Schedules, Students } from './Containers';

export const routes = <div>
  <DefaultLayout exact path="/" component={Dashboard} />
  <DefaultLayout path="/matters" component={Matters} />
  <DefaultLayout path="/schedules" component={Schedules} />
  <DefaultLayout path="/students" component={Students} />
</div>;
Run Code Online (Sandbox Code Playgroud)

  • 请接受此为正确答案。它很干净,遵循当前的 React 模式并使用 Typescript。 (3认同)

cbr*_*ino 5

我认为布局不属于路线文件。

保持路线清洁,即:

<Route exact path="/" component="HomePage" />
Run Code Online (Sandbox Code Playgroud)

然后,在HomePage组件中,将渲染的内容包装在您选择的布局中:

...
render() {
  <PublicLayout>
    <h1>Home page!</h1>
  </PublicLayout>
}
Run Code Online (Sandbox Code Playgroud)

这样,路由就可以保持超级干净,此外,您还可以通过一种简单的方法来显示应该同时支持两种布局的路由(例如404页)。

  • 想象一个应用程序具有数十条或一百多条路线,这意味着您必须为每个路线重复一次包装布局。只是尝试使其保持干燥。 (4认同)
  • 这应该是公认的答案。是的,如果您有大量的路由,您将有一些重复的代码(我们每次只说3条tbh),但它有一些优点:布局和布线分别(这是两个不同的问题),更具说明性( (React方式),减少了多余的包装&lt;div&gt;。顺便说一句,大多数应用程序都不会处理一百多个路线,即使那样,布局也不是您的第一个问题:) (2认同)

Pet*_*tas 5

我会在任何被问到这个问题的地方写这个,如果你在其他地方看到过,很抱歉。我这样做只是因为我已经挣扎了一段时间,我认为尽可能多地传播这个解决方案是值得的。够了,这就是我所做的,我认为这是不言自明的。就像一个魅力,它很容易打字。

const withLayout = (LayoutComp, ComponentComp) => <LayoutComp><ComponentComp /></LayoutComp>;
const withDefaultLayout = (ComponentComp) => () => withLayout(Layout, ComponentComp);
const withEmptyLayout = (ComponentComp) => () => withLayout(EmptyLayout, ComponentComp);

export const routes = <div>
    <Switch>
        <Route path="/" exact render={withDefaultLayout(Home)} />
        <Route path='/subscriptions' render={withDefaultLayout(SubscriptionsWrapped)} />

        <Route path='/callback' render={withEmptyLayout(AuthCallback)} />
        <Route path='/welcome/initial' render={withEmptyLayout(Start)} />
    </Switch>
</div>;
Run Code Online (Sandbox Code Playgroud)


Flo*_*elt 1

更新:我用另一种方式解决了这个问题,但是如果强制您使用 /app 或 /admin 为应用程序的不同部分命名。

UserRoutes、AdminRoutes 和 PublicRoutes 中的每个组件基本上都是大型 Switch 组件,其根部具有特定布局。

它看起来是这样的:

<Router>
  <Switch>
    <Route path="/app" render={props => <UserRoutes {...props} />} />
    <Route path="/admin" render={props => <AdminRoutes {...props} />} />
    <Route path="/" render={props => <PublicRoutes {...props} />} />
  </Switch>
</Router>
Run Code Online (Sandbox Code Playgroud)

旧:一种解决方案是使用每个 Route 的 render prop,但这看起来确实很麻烦:

<Router>
  <Switch>
    <Route
      path="/"
      render={() => <PublicLayout><HomePage /></PublicLayout>}
    />
    <Route
      path="/about"
      render={() => <PublicLayout><AboutPage /></PublicLayout>}
    />
    <Route
      path="/profile"
      render={() => <PrivateLayout><ProfilePage /></PrivateLayout>}
    />
    <Route
      path="/dashboard"
      render={() => <PrivateLayout><DashboardPage /></PrivateLayout>}
    />
  </Switch>
</Router>
Run Code Online (Sandbox Code Playgroud)