【问题标题】:Nested routes and not found route in react router dom v5react router dom v5中的嵌套路由和未找到路由
【发布时间】:2020-10-10 17:14:26
【问题描述】:

在尝试在 react router dom v5 中创建嵌套路由时,我发现 this answer 解释了如何很好地做到这一点

(请看这里的代码,因为它与上面提到的答案有点不同)

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>
  );
}

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} />
      {/* Commenting this because I want to go to NotFound component */}
      {/* <Redirect from="/auth" to="/auth/login" exact /> */}
    </div>
  );
}

应用布局

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} />
      {/* Commenting this because I want to go to NotFound component */}
      {/* Redirect from="/app" to="/app/home" exact /> */}
    </div>
  );
}

但是这有一个问题,如果你使用/app/somethingnotfound 去一个路由它不会去&lt;Route path="/" component={NotFound} /&gt;,它会“留在里面”AppLayout 并且不渲染任何路由。

在这种情况下如何让/app/somethingnotfound 转到&lt;Route path="/" component={NotFound} /&gt;

编辑:

更清楚一点:我不想在AuthLayoutAppLayout 中添加&lt;Route component={NotFound} /&gt;,因为它会渲染其他内容。我真正需要的是展示顶级NotFound

【问题讨论】:

    标签: reactjs react-router react-router-dom react-router-v5


    【解决方案1】:

    未找到的组件通常是这样工作的:

    <Router>
      <Switch>
        <Route exact path="/auth" component={AuthLayout} />
        <Route exact path="/app" component={AppLayout} />
        <Route component={NotFound} />
      </Switch>
    </Router>
    

    但您不能将/auth/app 标记为exact,因为它们包含嵌套路由。所以,你应该这样做:

    <Router>
      <Switch>
        <Route path="/auth" component={AuthLayout} />
        <Route path="/app" component={AppLayout} />
        <Route exact path="/404" component={NotFound} />
        <Redirect to='/404' />
      </Switch>
    </Router>
    

    和你的组件(例如AppLayout)嵌套路由:

    <>
    <h1>App Layout</h1>
    <Switch>
      <Route path="/app/home" exact component={Home} />
      <Route path="/app/dashboard" exact component={Dashboard} />
      <Redirect to="/404" />
    </Switch>
    </>
    

    【讨论】:

    • 我在问题中说过,但我认为不是很清楚,我的意思是“我怎样才能让 /app/somethingnotfound 转到 在这种情况下?”意味着我想从Layouts 组件中显示NotFound 组件,因为您正在这样做,它显示了AppLayout 中的所有内容(如果您删除了它,但它会显示&lt;h1&gt;App Layout&lt;/h1&gt;)这不是我需要的
    【解决方案2】:

    在查看 github 问题时,我发现了 this solution,您创建了一个“全局未找到页面”,如果找不到路由,则在该页面中传递状态,然后只渲染它而不是其他路由。

    const NotFound = () => <div className="not_found"><h1>Not Found</h1></div>;
    
    const RouteNotFound = () => <Redirect to={{ state: { notFoundError: true } }} />;
    
    const CaptureRouteNotFound = withRouter(({children, location}) => {
      return location && location.state && location.state.notFoundError ? <NotFound /> : children;
    });
    
    const Settings = () => {
      return (
        <Switch>
          <Route path="/settings/account" render={() => <h1>Account Settings</h1>} />
          <Route path="/settings/profile" render={() => <h1>Profile Settings</h1>} />
    
          <RouteNotFound />
        </Switch>
      );
    };
    
    const AppShell = ({children}) => {
      return (
        <div className="application">
          <header>Application</header>
          {children}
        </div>
      );
    };
    
    const Application = () => {
      return (
        <Router>
          <CaptureRouteNotFound>
            <AppShell>
              <Switch>
                <Route path="/settings" render={() => <Settings />} />
                <Route path="/profile" render={() => <h1>User Profile</h1>} />
    
                <RouteNotFound />
              </Switch>
            </AppShell>
          </CaptureRouteNotFound>
        </Router>
      );
    };
    

    【讨论】:

      【解决方案3】:

      &lt;Route path="/" component={NotFound} /&gt; 不匹配所有未实现的嵌套,因为Layouts 组件中的Switch 只会呈现与pathname 匹配的第一个Route 子级。在您的情况下,当您转到路径 /app/somethingdoesntexist 时,它会将路径与 AppLayout 组件匹配,这就是它只呈现 AppLayout 组件的原因。

      解决方案

      最好使用嵌套的Switch组件为每个布局实现NotFound路由,例如

      function AppLayout() {
        const { path, url } = useRouteMatch();
      
        return (
            <Switch>
              <Route path={`${path}/home`} exact component={Home} />
              <Route path={`${path}/dashboard`} exact component={Dashboard} />
              <Route path="*" component={NotFound} />
            </Switch>
        );
      }
      

      在上面的例子中,我们通过使用useRouteMatch钩子获得了匹配的路径,并嵌套了另一个Switch组件,该组件将呈现与path匹配的任何嵌套路由,我们提供了一个备用Route指定路径为"*" 将在找不到匹配项时呈现 NotFound 组件。

      这是一个完整的解决方案示例codesandbox

      您还可以查看文档中提供的嵌套example

      【讨论】:

      • 我在问题中说过,但我认为不是很清楚,我的意思是“我怎样才能让 /app/somethingnotfound 转到 在这种情况下?”意味着我想从Layouts 组件中显示NotFound 组件,因为您正在这样做,它显示了AppLayout 中的所有内容(如果您删除了它,但它会显示&lt;h1&gt;App Layout&lt;/h1&gt;)这不是我需要的
      • 是的,如果您在AppLayout 的嵌套开关之外渲染它,它将显示&lt;h1&gt;App Layout&lt;/h1&gt;。但是你绝对需要在开关外渲染 h1 吗?您可以使用另一条路线将 h1 呈现在内部作为基本路径并获得相同的确切结果,或者它不是您需要的。我仍然不清楚您要达到的确切结果。请查看答案中的代码框,如果它不满足结果,请告诉我它失败的地方。
      • 我已经更新了答案中的codesandbox。请看一下,如果不能满足您的需求,请告诉我。
      猜你喜欢
      • 2021-12-30
      • 2020-02-12
      • 2021-03-02
      • 2020-10-14
      • 2018-01-28
      • 2022-01-13
      • 1970-01-01
      • 2017-08-16
      • 1970-01-01
      相关资源
      最近更新 更多