【问题标题】:React router does not render route when URL accessed directly直接访问 URL 时 React 路由器不渲染路由
【发布时间】:2021-02-18 13:06:07
【问题描述】:

考虑这是主要的 App 组件(为简洁起见省略了导入):

const App = () => {
    const [orderRoutes, setOrderRoutes] = useState([])

    const updateOrderRoutes = (newRoute) => {
        orderRoutes.push(newRoute)
        setOrderRoutes(orderRoutes)
    }

    const renderedOrderRoutes = orderRoutes.map(route => {
        return (
            <Route
                path={`/${route.class}/${route.order}`}
                exact
                key={`/${route.class}/${route.order}`}
            >
                <CatalogPage />
            </Route>
        )
    })

    return (
        <BrowserRouter>
            <Header
                updateOrderRoutes={updateOrderRoutes}
            />
            <Route path="/" exact component={Home} />
            <Route path="/aboutus" exact component={AboutUs} />
            <Route path="/faq" exact component={Faq} />
            <Route path="/register" exact component={Register} />
            {renderedOrderRoutes}
            <Footer />
        </BrowserRouter>
    )
}

export default App

挑战在于,在渲染初始 App 组件时,某些路由是未知的。当&lt;Header&gt; 组件中的 AJAX 请求得到响应时,它们将被知道。然后,标头会将新路由更新到 orderRoutes 状态属性,每次都重新渲染 App 组件。作为 AJAX 调用结果的路由(在 &lt;Header&gt; 中生成)然后被渲染到 &lt;BrowserRouter&gt;(在 {renderedOrderRoutes} 中)。在&lt;Header&gt; 中,由于相同的 AJAX 调用而呈现的每个路由都有一个&lt;Link&gt;,因此每个菜单条目(&lt;Link&gt;s)都会有一个对应的路由。

这很好用,但是当我访问此机制直接生成的 URL 之一(例如:刷新页面)时,&lt;CatalogPage&gt; 组件不会呈现。

因此,例如,假设 AJAX 调用产生了一堆路由,其中​​一个是 /t-shirts/tanktops。我将获得一个菜单条目,其中包含指向该路径的链接。当我单击该菜单项时,将呈现 &lt;CatalogPage&gt; 组件。但是当我直接访问/t-shirts/tanktops 时,&lt;CatalogPage&gt; 组件并没有呈现出来。

如何更改此代码以使作为 AJAX 调用结果的 URL 可直接访问?

编辑

好的,我通过在&lt;Link&gt;s 之一通过在App 组件上创建未使用的状态来单击时强制&lt;App&gt; 组件重新渲染来“解决”这个问题(不喜欢它)叫activeOrderRoute。我将 setter 作为 prop 传递给 Header,并将它作为回调连接到为响应 AJAX 请求而创建的每个 LinkonClick 处理程序。这实质上迫使App 重新渲染和渲染路线,这解决了我的问题。

不过,这似乎不是正确的方法,因此我们将不胜感激。

【问题讨论】:

  • 我已经回答了如何处理渲染可访问路由的问题,但似乎您在 AppHeader 组件之间也有一个奇怪的解决方法,可以踢其中一个或两个重新渲染显示“新”路线的链接。您能否更新您的问题以包含路由获取逻辑以及AppHeader 的相关部分?
  • 这个问题可能与stackoverflow.com/q/27928372/470749重复

标签: reactjs react-router-dom


【解决方案1】:

React 路由器并不直接支持所有 URL 的路由。它仅捕获默认域,仅在客户端完成剩余路由并且不提供请求。 如果你的域是www.mydomain.com,你不能直接在react路由器中访问URLwww.mydomain.com/info。 解决方案:

  1. 您可以使用哈希路由器,但这会使 URL 对 SEO 不友好
  2. 您可以设置一条包罗万象的路线并自行安排路线

这个链接可以帮助你 https://ui.dev/react-router-cannot-get-url-refresh/

【讨论】:

  • 感谢您的帮助,但我不明白您的意思。您所说的“请求未得到处理”是什么意思?
  • 基本上你的服务器不知道路由 www.mydomain.com/info 甚至存在,它只知道客户端反应代码与反应路由器。因此,当任何用户向 www.mydomain.com/info 发出请求时,他们不会得到预期的响应(他们不会得到服务)。您的服务器仅解析 react 应用的主页/索引页面
  • 我明白这一点。我使用路径(在您的示例中为:'/info')在路由器路径中呈现正确的组件 以获取执行 AJAX 请求的参数。然后我更新&lt;CatalogPage&gt; 组件的状态以使用获取的信息重新渲染它。问题是,我是否需要强制更新 &lt;App&gt; 组件的重新渲染,但也许这是 React 中的正常工作流程?
  • 这是一个正常的工作流程,是的,这也是大多数 fetch 请求的工作方式,所以这不是问题,并且组件重新渲染确实对 react 没有那么重,但请记住,您不会更新任何这些在使用中的函数可以避免无限循环。
  • 好的,我想我需要一个范式转变。我试图尽可能避免重新渲染,但你是对的:这不是一个密集的操作。
【解决方案2】:

您需要修改您的 webpack.config.js 并添加以下行。

module.exports = {
  devServer: {
    historyApiFallback: true,
  },
  ...

【讨论】:

  • 我对 webpack 配置不熟悉,但这是否只在编译开发时设置此选项?
【解决方案3】:

与其尝试为每个异步获取的路由显式渲染路由,不如利用 react-router-dom 的强大功能并渲染可以处理任何目录页面的动态路由 path string

而不是这个:

const renderedOrderRoutes = orderRoutes.map(route => {
  return (
    <Route
      path={`/${route.class}/${route.order}`}
      exact
      key={`/${route.class}/${route.order}`}
    >
      <CatalogPage />
    </Route>
  )
})

return (
  <BrowserRouter>
    <Header
      updateOrderRoutes={updateOrderRoutes}
    />
    <Route path="/" exact component={Home} />
    <Route path="/aboutus" exact component={AboutUs} />
    <Route path="/faq" exact component={Faq} />
    <Route path="/register" exact component={Register} />
    {renderedOrderRoutes}
    <Footer />
  </BrowserRouter>
)

在您的 Router 中呈现单个动态路由。使用Switch,因此只有一个路由组件被匹配和渲染。重新排序路线,以便更具体的路径可以匹配之前不太具体的路径。现在,当 URL 的路径具有 "/someClass/someOrder" 形状时,可以在尝试匹配任何更通用的路径之前对其进行匹配。您将看到主路径 ("/") 最后匹配,并且重新排序允许我们删除所有路由上的 exact 属性。

return (
  <BrowserRouter>
    <Header updateOrderRoutes={updateOrderRoutes} />
    <Switch>
      <Route
        path="/:class/:order"
        exact
        component={CatalogPage}
      />
      <Route path="/aboutus" component={AboutUs} />
      <Route path="/faq" component={Faq} />
      <Route path="/register" component={Register} />
      <Route path="/" component={Home} />
    </Switch>
    <Footer />
  </BrowserRouter>
)

您可能需要调整 CatalogPage 中的一些逻辑以处理可能的未定义目录数据,无论它使用来自路由 props/etc... 来呈现目录内容。

在您的Header 组件中进行异步调用以获取可以导航到的路由,以便您可以动态呈现指向它们的渲染链接(如果这就是您将路由传递给Header 的原因) )。

【讨论】:

  • 真的很有帮助。需要更新我的反应路由器掌握。好的提示,谢谢
  • @GuidoGoluke 这个答案是否有助于至少部分解决您的问题?我怀疑我们可以通过AppHeader 之间的相互作用做更多的事情。如果您想在问题中添加更多示例代码,我们可以尝试完全解决您的问题。
  • 我已经解决了 App 和 Header 之间的相互作用,只需将 useState 设置器作为道具传递并触发 App 的重新渲染就可以了。我认为我需要更好地理解 React Router 能做什么和不能做什么,以及它是如何解决警告的。我只是对此知之甚少。我确实想知道为什么某些“链接”组件不会触发重新渲染,但我认为这属于同一类别。感谢您的帮助。
  • 嗯,链接不直接更新状态和/或道具,但取决于路由设置和匹配的内容可以改变正在呈现的内容。渲染动态路径时,您只需从一个匹配参数转到另一个匹配参数,即就像只是转到不同的 id,然后渲染的组件不会重新安装,因此如果需要,它需要处理来自 props/routing 上下文的更新参数使用不同的数据/用户界面/等重新渲染。
  • 感谢您的所有帮助。我有一些功课要做!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-25
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
相关资源
最近更新 更多