我想在我的公共布局中渲染我的一些路线,以及我的私人布局中的其他一些路线,是否有一种干净的方法可以做到这一点?
显然不起作用的例子,但我希望大致解释一下我在寻找的内容:
<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>
我希望切换某些路线的布局,如何使用新的路由器做到这一点?
嵌套路由不再有效并且给我这个错误:
You should not use <Route component> and <Route children> in the same route; <Route children> will be ignored
编辑:布局包裹整组路线也意味着只要您保留在同一个私人/公共路线组中,这些布局只会呈现一次。如果您的布局必须从您的服务器获取某些内容,这是一个大问题,因为如果您使用布局包装每个页面,那么每次更改都会发生这种情况。
答案 0 :(得分:25)
我为此做的是创建一个简单的组件,为Route组件添加一个额外的属性,即布局:
function RouteWithLayout({layout, component, ...rest}){
return (
<Route {...rest} render={(props) =>
React.createElement( layout, props, React.createElement(component, props))
}/>
);
}
然后在您的情况下,您的路线将如下所示
<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>
答案 1 :(得分:6)
如果您使用的是 Typescript ,并希望关注this react layout aproach,那么您可以按照以下方式声明您的布局:
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;
并声明这样的路线:
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>;
答案 2 :(得分:4)
寻找干净,高效的方法(避免滥用重新渲染):
<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>
aslo,可以重构, 看到我完整的答案: https://stackoverflow.com/a/57358661/3437790
答案 3 :(得分:3)
我不认为布局属于路径文件。
保持路线清洁,即:
<Route exact path="/" component="HomePage" />
然后,在HomePage
组件中,将呈现的内容包装在您选择的布局中:
...
render() {
<PublicLayout>
<h1>Home page!</h1>
</PublicLayout>
}
这样路线保持超级干净,而且你可以轻松地显示应该支持这两种布局的路线(例如404页)。
答案 4 :(得分:2)
我尝试了Florians的回答,但这对我来说还不够,因为反应将为每条路线创建一个单独的布局实例,因此任何导航过渡都会被杀死。
我希望有一个更优雅的解决方案,但这让我的应用程序再次使用v4。
定义一个指向组件的Route,该组件将决定在
中包装路径的内容<Router>
<Route component={AppWrap} />
</Router>
在AppWrap中执行以下操作
var isPrivateLayout;
for (var path of listOfPrivateLayoutPaths) {
if (this.props.location.pathname == path) {
isPrivateLayout= true;
}
}
if (isPrivateLayout) {
return <PrivateLayout>
(routes)
</PrivatelyLayout>
} else {
return <PublicLayout>
(routes)
</PublicLayout>;
}
Route Config也许可以用来更清晰地表示这一点,不确定。
答案 5 :(得分:2)
如果您在其他地方看过这个问题,我会在任何地方写这个问题。 我只是这样做,因为我已经挣扎了一段时间,我认为值得尽可能地传播这个解决方案。 足够的话,这就是我所做的,我认为这是非常自我解释的。像魅力一样工作,它很容易打字。
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>;
答案 6 :(得分: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>
旧:一种解决方案是使用每条路线的渲染道具,但它看起来真的很麻烦:
<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>
答案 7 :(得分:1)
这个想法与Zaptree的想法相同,但使用es6语法并添加了检查,因此可以用它代替react-router的Route组件
创建一个新组件,比如说/src/components/Route/index.js:
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {Route as ReactRoute} from 'react-router'
class Route extends Component {
static propTypes = {
component: PropTypes.func.isRequired,
layout: PropTypes.func,
path: PropTypes.string,
exact: PropTypes.bool
}
render = () => {
const {component, layout, path, exact} = this.props
let routeComponent = props => React.createElement(component, props)
if (layout) {
routeComponent = props =>
React.createElement(layout, props, React.createElement(component, props))
}
return <ReactRoute path={path} exact={exact} render={routeComponent}/>
}
}
export default Route
使用创建的Route组件:
import Route from 'components/Route/'
...
<Router history={createHistory()}>
<Switch>
<Route exact path='/' layout={PublicLayout} component={HomePage}/>
<Route exact path='/' layout={PrivateLayout} component={ProfilePage}/>
<Route path='/logins' component={Login}/>
</Switch>
</Router>
答案 8 :(得分:0)
使用Route组件的渲染道具,这不会在每次更改路线时卸载并安装布局组件。 here的工作原理的更多详细信息。
假设您有两个布局组件 Primary.js 和 Secondary.js
在您的 App.js 呈现方法中,您只需返回
<BrowserRouter>
<Switch>
<Route path='/login' render={() => <Secondary><Login/></Secondary>} />
<Route path='/dashboard' render={() => <Primary><Dashboard/></Primary>} />
</Switch>
</BrowserRouter>
要进一步完善它,您还可以定义一个高阶组件布局组件,以用布局包装页面组件。 (未测试)
<Route to='/login' render={() => Secondary(Login)}
答案 9 :(得分:-1)
@Qop是正确的,但是在新的React路由器中,我注意到如果你在交换机内部有你的根路径,它将始终与它匹配,因此永远不会显示你的后续路由。您应该将根路径放在最后。
<Switch>
<RouteWithLayout layout={PublicLayout} path="/about" component={AboutPage}/>
<RouteWithLayout layout={PrivateLayout} path="/profile" component={ProfilePage}/>
<RouteWithLayout layout={PrivateLayout} path="/dashboard" component={DashboardPage}/>
<RouteWithLayout layout={PublicLayout} path="/" component={HomePage}/>
</Switch>
答案 10 :(得分:-2)
与@Zaptree相同的想法
布局
function PublicLayout(props) {
return (
<Route {...props} />
);
}
function PrivateLayout(props) {
return (
<Route {...props} />
);
}
路线
<Switch>
<PublicLayout exact path="/" component={HomePage} />
<PrivateLayout path="/profile" component={ProfilePage} />
<Route path="/callback" component={NoLayoutPage} />
</Switch>
答案 11 :(得分:-2)
此解决方案可行。
<Router>
<Switch>
<PublicLayout>
<Route exact path="/" component={HomePage} />
<Route exact path="/about" component={AboutPage} />
</PublicLayout>
</Switch>
<Switch>
<PrivateLayout>
<Route exact path="/profile" component={ProfilePage} />
<Route exact path="/dashboard" component={DashboardPage} />
</PrivateLayout>
</Switch>
</Router>