使用 Reach Router 导航到 404 路由

Navigating to a 404 Route with Reach Router

我有以下路由配置:

<Router>
 <NotFound default />
 <ResourcesContainer path="/resources" />
 <ResourceContainer path="/resources/:id" />
 ...
</Router>

这会捕获任何未处理的路由,并在未找到的 URL 处呈现 <NotFound /> 组件,因此如果我键入 example.com/blah,我会看到 <NotFound /> 组件呈现,在地址栏中我看到 example.com/blah。我也在页面上用这个URL来显示一条信息:

The page 'example/blah' was not found.

到目前为止一切顺利。但是,我还需要在 /resources/* 路由中处理 404。我的 <ResourcesContainer/> 组件使用路径的最后一部分为具有该 ID 的资源命中 GraphQL API。如果 API returns 告诉客户端资源不存在,我想模仿上面概述的行为。但是,我没有要 navigate 的页面。我可以复制 <NotFound /> 路由并给它一个 /404 的显式 path,然后导航到那个。然而 URL 将是 /404 而不是未找到的原始 resources/* 路径。

以下解决了部分问题,给我一个重定向 ot 的页面,但意味着 URL 在所有情况下都被重写为 /404

<Router>
 <ResourcesContainer path="/resources" />
 <ResourceContainer path="/resources/:id" />
 <NotFound path="/404" />
 <Redirect noThrow from="*" to="/404" />
 ...
</Router>

我该如何设置才能navigate<NotFound />路线而不丢失原来的URL?

我认为这不是路由问题。渲染 /resources/:id 的组件基本上有三种状态:loadingfoundData404。如果您只是为每个状态渲染不同的组件,那么您可以只渲染相同的 404 组件。很简单,如果您不想更改 url,请不要导航。

如果找不到资源,最好的选择是将 ResourceContainer 的呈现方法更改为呈现 NotFound

但是,如果您不想对 ResourceContainer 进行更改,您可以像这样用 error boundary 将其包装起来:

class NotFoundErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { notFound: false };
  }

  static getDerivedStateFromError(error) {
    // Filter which kind of errors you want to show the error boundary for
    return { notFound: true };
  }

  render() {
    if (this.state.notFound) {
      // You can render any custom fallback UI
      return <NotFound />;
    }

    return this.props.children; 
  }
}

并像这样使用它:

<NotFoundErrorBoundary>
 <ResourceContainer path="/resources/:id" />
</NotFoundErrorBoundary>

您的 ResourceContainer 可以抛出一个错误 NotFoundErrorBoundary 可以识别并且可以发出未找到资源的信号,它应该呈现 NotFound 页面而不是子页面。

需要说明的是,我并不是鼓励您使用 ErrorBoundary。在我看来,这会使事情过于复杂。我只是给你提供信息,你如何使用它取决于你。根据用例,它在其他上下文中也可能对您有用。

错误边界不是处理它的好选择。官方网站鼓励我们使用嵌套路线理念,例如最佳做法是在每个 child 中使用 <Router>: 根:

<Router>
 <NotFound default />
 <ResourcesContainer path="/resources/*" />
 ...
</Router>

ResourcesContainer.jsx:

<Router>
 <NotFound default />
 <ResourcesList path="/" />
 <ResourceDetail path="/:id" />
 ...
</Router>

如果我们在 API 调用中得到 404,如何渲染 <NotFound /> 很简单:

if (API.error) return <NotFound />;
if (API.data) return ...;

如何简化呢? 我们可以像这样有一个包装器: 没有找到路由器

<Router>
 <NotFound default />
 {children}
</Router>