React Router v5.0 嵌套路由

ET-*_*-CS 7 reactjs react-router

我正在构建一个反应应用程序,但我无法使路由工作。

  1. 我需要一些验证途径一个共同的布局(页眉,页脚)( ,/loginsign-upforgot-password等...)

  2. 我需要需要另一种常见的布局应用程序的保护部分的剩余部分(HomeDashboard,等...)

  3. 我需要另一个没有任何布局的 404 页面。

我从这些链接中尝试了几种技术:

但可以达到工作版本。

这是我目前拥有的:

(注意:现在我忽略了阻止非登录用户进入 AppLayout 的私有路由的需要,我会在之后处理这个问题)

const App: React.FC = () => {
    const history = createBrowserHistory();

    return (
        <div className="App">
            <Router history={history}>
                <Switch>
                    <AppLayout>
                        <Route path="/home" component={HomePage}/>
                        <Route path="/dashboard" component={DashboardPage}/>
                        ...
                    </AppLayout>
                    <AuthLayout>
                        <Route path="/login" component={LoginPage}/>
                        <Route path="/sign-up" component={SignUpPage}/>
                        ...
                    </AuthLayout>
                    <Route path="*" component={NotFoundPage} />
                </Switch>
            </Router>
        </div>
    );
};

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

AuthLayoutAppLayout简单,类似于(只是对于每个不同的页眉/页脚):

class AppLayout extends Component {
    render() {
        return (
            <div className="AppLayout">
                <header>...</header>
                {this.props.children}
                <footer>...</footer>
            </div>
        );
    }
}

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

问题是只呈现来自 AppLayout 的路由。其他路由只显示 AppLayoutheaderfooter没有任何内容。

这些是我正在使用的反应版本:

    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-router-dom": "^5.0.0",
Run Code Online (Sandbox Code Playgroud)

任何帮助,将不胜感激。

提前致谢。

joh*_*ter 19

Each of your layout should have a path component to differentiate from other layouts.

For example

Auth layouts could reside under /auth eg, login would /auth/login, signup would be /auth/signup

App layout could go under /app eg, dashboard would be /app/dashboard, home would be /app/home

Working Demo

编辑饥饿杜宾斯基-q1l62

App.js

import { Switch, BrowserRouter, Route, Redirect } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Layouts />
    </BrowserRouter>
  );
}
Run Code Online (Sandbox Code Playgroud)

Layouts.js

const NotFound = () => <h1>Not Found</h1>;

function Layouts() {
  return (
    <Switch>
      <Route path="/auth" component={AuthLayout} />
      <Route path="/app" component={AppLayout} />
      <Route path="/" component={NotFound} />
    </Switch>
  );
}
Run Code Online (Sandbox Code Playgroud)

AuthLayout

const Signup = () => <p>Login</p>;
const Login = () => <p>Sign up</p>;

function AuthLayout() {
  return (
    <div>
      <h1>Auth Layout</h1>
      <Route path="/auth/signup" exact component={Signup} />
      <Route path="/auth/login" exact component={Login} />
      <Redirect from="/auth" to="/auth/login" exact />
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

AppLayout

const Home = () => <p>Home</p>;
const Dashboard = () => <p>Dashboard</p>;

function AppLayout() {
  return (
    <div>
      <h1>App Layout</h1>
      <Route path="/app/home" exact component={Home} />
      <Route path="/app/dashboard" exact component={Dashboard} />
      <Redirect from="/app" to="/app/home" exact />
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

Also if you want to protect certain routes from being rendered if not authenticated, then you can create a PrivateRoute component that would redirect to auth layout if not authenticated.

PrivateRoute.js

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route
    {...rest}
    render={props => sessionStorage.token // your auth mechanism goes here
      ? <Component {...props} />
      : <Redirect to={{ pathname: '/auth' }} />}
  />
);
Run Code Online (Sandbox Code Playgroud)

You can use this PrivateRoute component instead of react-router's Route component.

Eg:

<PrivateRoute path="/app" component={AppLayout} />

  • 这个解决方案帮助我弄清楚了。在我看来,这比接受的答案更好。 (2认同)

ET-*_*-CS 5

我花了一些时间才找到我喜欢的答案。@johnny-peter 和 @gaurab-kc 解决方案都很棒,他们让我了解 React 的路由机制。

@johnny-peter 的解决方案的缺点是迫使我auth/auth/...(例如/auth/login& auth/sign-up)下为所有相关路由添加我不想要的前缀。

@gaurab-kc 解决方案只支持一组路线..所以如果用户已经注册,他就不能再访问该/login路线了。

直到最近,我使用了自己的解决方案,该解决方案存在“破坏了通用页眉和页脚的全部目的”的问题。正如@johnny-peter 所提到的,它应该被否决了几次。

现在我正在使用另一种解决方案:

<Router history={browserHistory}>
    <Switch>
        <Redirect exact from="/" to="/home"/>
        <Route exact path={["/login", "/sign-up", ...]}>
            <AuthLayout>
                <Switch>
                    <Route
                        path="/login"
                        component={LoginPage}
                    />
                    <Route
                        path="/sign-up"
                        component={SignUpPage}
                    />
                </Switch>
            </AuthLayout>
        </Route>
        <Route exact path={[
            "/home",
            "/dashboard",
            ...
        ]}>
            <SiteLayout>
                <Switch>
                    <Route
                        path="/home"
                        component={HomePage}
                    />
                    <Route
                        path="/dashboard"
                        component={DashboardPage}
                    />
                </Switch>
            </SiteLayout>
        </Route>
        <Route path="*" component={NotFoundPage}/>
    </Switch>
</Router>
Run Code Online (Sandbox Code Playgroud)

这可以防止上述所有缺点。它允许我:

  1. 为每个部分使用布局,在路线更改时不会重新渲染。
  2. 不强迫我为路由添加任何前缀。
  3. 所有路由同时工作,让用户无需先注销即可路由回该路由/login或其他auth路由。

此解决方案的唯一缺点是代码较多且路线重复,但这是我愿意支付的成本。