【问题标题】:React Router Routing three levels deep, Only works in App.js fileReact Router Routing 三层深度,仅适用于 App.js 文件
【发布时间】:2021-04-01 05:16:44
【问题描述】:

我正在建立一个具有以下链接结构的网站:

  1. /blog
  2. /blog/post1
  3. /preview

/blog url 列出了所有博客帖子,/blog/post1 在编辑视图中显示帖子,同一编辑视图中的预览按钮链接到/preview url,显示编辑版本的预览。 我最初的想法是使用/blog/post1/preview url,但是使用<Switch> 变得复杂了。它不起作用,因为整个exact 问题我必须正确匹配三个以相同地址开头的网址。所以我切换到/preview。现在,我可以让第一个 url 工作,但 /preview 在屏幕上没有呈现任何内容。是因为我的<Link><Route> 在我的应用程序中定义的位置。我有以下结构:

  <Switch>
     <Route path='/blog'>
       <Blog/>
     </Route>
   <Switch>

in the main app.js

     <Route exact path='/blog'>
       //div with some helper views like search bar
     </Route>

     //it is inside map function that renders a card view of many posts, post1 for simplicity
     <Route path='/blog/post1'>
       <PostEditor/>
     </Route>

in the main Post.js component

     <Route path='/preview'>
       //Content
     </Route>

in the main PostEditor.js PostEditor.js 在同一个文件中有LinkRoute 标签,但在其他文件中没有。这是它什么都不渲染的原因吗?当我将Route 标签从PostEditor 移动到App.js 时,一切正常。是嵌套问题还是类似的问题。我尝试在网上搜索,但对多层嵌套没有太多运气,通常是两层。任何帮助是极大的赞赏。
我正在使用 react-router 5.2.0 和 HashRouter,因为它与 github 配合得更好

更新: 我添加了一个示例沙箱来模拟我的场景。为什么在这种情况下/preview 链接不呈现任何内容?我想知道在这种情况下我做错了什么,因为我觉得关于 react-router 的某些知识存在差距,而我在不同级别创建链接和路由时缺少这些知识?此外,处理我目前正在做的事情的最佳选择是什么。


Code SandBox

【问题讨论】:

  • 在代码沙盒或任何其他在线代码编辑器中显示此类问题总是一个好主意。这样我们就可以更好地了解您是如何使用 Route 和 Switch 以及 Links 的。
  • 我添加了示例代码链接。这可能更好地解释这种情况。为什么我在预览页面上看不到任何内容?

标签: javascript reactjs debugging react-router react-router-dom


【解决方案1】:

我在这里看不到任何路由嵌套,但我怀疑您遇到的问题是路径特异性和顺序。

Switch 中,您应该订购路线以列出更具体的路径不太具体的路径之前。回想一下 Switch 返回并呈现第一个匹配项是 finds,因此通过首先尝试匹配更具体的路径,您可以避免意外匹配不太具体的路径前缀。换句话说,“/blog”是其他子路由的路径前缀,所以你要最后匹配它。

  1. "/blog/:postId/preview"
  2. "/blog/:postId"
  3. "/blog"

代码:

<Switch>
  <Route path='/blog/:postId/preview'>
    //Content
  </Route>
  <Route path='/blog/:postId'>
    <PostEditor/>
  </Route>
  <Route path='/blog'>
    <Blog/>
  </Route>
<Switch>

编辑

为什么在这种情况下 /preview 链接不呈现任何内容?我会 想知道在这种情况下我做错了什么,因为我觉得有 关于我缺少的有关 react-router 的知识差距 关于在不同级别创建链接和路由?

“/preview”链接不呈现任何内容,因为在“/blog/post1”(即Post)上呈现的组件现在不再被呈现。换句话说,URL 更新为“/preview”,Post 被卸载。由于根目录中没有“/preview”路由,因此没有匹配和渲染任何内容。

基于您添加的代码框的解决方案

你当然可以nest routes。以下是我建议正确嵌套博客路由的更改。

App.js - 特殊性和顺序很重要,将更具体的根路径放在之前不太具体的路径。

<Switch>
  <Route path="/blog">
    <Blog />
  </Route>
  <Route path="/">
    <Home />
  </Route>
</Switch>

Blog.js - 将嵌套路由渲染到另一个 Switch 组件中,再次注意路径的特异性和顺序。使用useRouteMatch 钩子访问当前的pathurl 属性,path 用于嵌套路由匹配,url 用于嵌套链接。请注意,来自Post 的预览路线已移至此处。

const Blog = () => {
  const { path, url } = useRouteMatch();
  return (
    <div className="blog">
      <Switch>
        <Route path={`${path}/:postId/preview`} exact>
          Blog Preview Before Save
          <br />
        </Route>
        <Route path={`${path}/post1`}>
          <Post />
        </Route>
        <Route path={path}>
          Blog Search Bar
          <br />
          <Link to={`${url}/post1`}>Post 1</Link>
        </Route>
      </Switch>
    </div>
  );
};

Post.js - 同样,从 useRouteMatch 访问 url 以构建到预览路由的嵌套链接。

const Post = () => {
  const { url } = useRouteMatch();
  return (
    <div className="post">
      <Link to={`${url}/preview`}>Preview</Link>
    </div>
  );
};

演示

注意:无论您是否“嵌套”Route 组件在总体方案中并不重要,整体路径结构将是相同的。您可以同样轻松(实际上可能更容易)在根级别定义所有您的路线,这是常见且完全可以接受的。如果您想在其他地方“嵌套”子路由,则可能需要在维护中进行权衡,您需要“查找并替换”所有特定的中间路径段,而“嵌套解决方案”只需要更新路径根/前缀。从这个意义上说,“嵌套解决方案”更具动态性。

【讨论】:

  • 感谢您的帮助。我添加了一个代码沙箱,可以更好地解释我想要做什么?
  • 另外,如果组件内部有路由,并且已经在routes标签中,不就是嵌套路由吗?
  • @Crypton99 如果您在其他Route 组件中确实有Route 组件,它 是嵌套路由。我添加了关于使用嵌套路由的答案。
  • 这成功了!感谢您抽出宝贵时间详细解释。欣赏!
【解决方案2】:

使用 route /preview 我们无法识别我们正在查看的博客。在下面粘贴最低工作路线配置

import React, {useState, useEffect} from 'react'
import {Link, BrowserRouter, Switch, Route, useParams} from 'react-router-dom'

#app.jsx
<Switch>
  <Route path="/blog" exact>
    <Blogs />
  </Route>
  <Route path="/blog/:id" exact>
    <PostEditor />
  </Route>
  <Route path="/blog/:id/preview">
    <Blog />
  </Route>
 </Switch>


const Blogs =  () => {
  return(
    <h1>Blog list</h1>
  )
}

const Blog = () => {
  const {id} = useParams()
  return(
    <h1>Blog {id}</h1>
  )
}

const PostEditor = () => {
  const {id} = useParams()
  return(
    <h1>Edit Blog {id}</h1>
  )
}

更新: 据我了解,您需要在没有路由开关的情况下在编辑表单后立即显示预览。为此,可以使用触发显示预览元素的按钮。

import React, {useState} from "react";
import { Route } from "react-router-dom";
import { HashLink as Link } from "react-router-hash-link";

const Post = () => {
  const [showPreview, setShowPreview] = useState(false);
  const [editData, setEditData] = useState('Some Post attributes')
  return(<div className="post">
      
    {showPreview ? <Preview editData={editData} /> : null}
    
    <button onClick={() => {setShowPreview(true)}}>Preview</button>
  </div>)
};
Preview = ({editData}) => {
  return(
    <h1>{editData}</h1>
  )
}
export default Post;

【讨论】:

  • 谢谢。我已经用链接编辑了这个问题。任何帮助表示赞赏。
猜你喜欢
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 1970-01-01
  • 2019-09-16
相关资源
最近更新 更多