react 路由详解, react-router-dom V6

  1. 路由介绍

    1. 因为SPA 页面,只有一个 HTMl 页面的应用程序, 用户的体验感更好,对于服务器的访问压力也更加好;
    2. 前端路由是一套映射规则,在 React 中,是 浏览器的URL 路径与组件的一 一对应关系;
    3. 一个路由就是一个映射关系(key:value) key为路径, value可能是function或component

  2. 路由功能

    1. 让用户能够从一个视图通过交互导航到另外的视图;
  3. react-router-dom v6 版本

    1. 安装
      1. 如果项目中还没有安装 React Router 则可以进行如下 NPM 安装,默认安装的就是 v6 版本 npm i react-router-dom
      2. npm i react-router-dom
  4. react-router-dom 路由模式

    1. 模式实现方式路由URL表现
      HashRouter监听url hash值实现http://localhost:3000/#/about
      BrowerRouterh5的 history.pushState API实现http://localhost:3000/about
    2. ​​​​​ Link:用于指定导航链接,完成声明式的路由跳转 类似于 Vue 中 <router-link />(渲染到 DOM 中它其实就是一个 a 链接):<Link to="your path"></Link>
    3. Routes:提供一个路由出口,组件内部会存在多个内置的 Route 组件,满足条件的路由会被渲染到组件内部,所以 Route 组件必须被Routes组件包裹才能展示(类比 vue 中的 router-view):
      <Routes>
      <Route path="your path" element={<Home />}></Route>
      </Routes>
    4. Route:用于定义路由路径 path 和渲染组件 element 的对应关系 [element:因为 react 体系内把组件叫做 react element]: 第三点有介绍
  5. react-router-dom V6 常用组件的介绍

    1.  <BrowserRouter>与<HashRouter> 
      <BrowserRouter> 组件用于包裹整个需要使用到路由组件的应用区域(一般用于包裹整个 <App />),它也表示当前路由模式为 BrowserRouter 模式;
    2. <BrowserRouter> 之外还可以使用 <HashRouter> 组件,用法相同,它表示当前路由模式为 HashRouter(具体表现为页面地址栏中会出现一个 /# )
  6. 代码实例
    1. import {
        BrowserRouter,
        Routes,
        Route,
        Link,
        useNavigate,
      } from "react-router-dom";
      
      function Home() {
        return <p>首页组件Home</p>;
      }
      
      function About() {
        // 用于函数式组件,用于类组件可能会报错
        const navigate = useNavigate();
        function goBack() {
          navigate("/");
        }
        return (
          <div>
            <div
              style={{
                width: "200px",
                height: "20px",
                backgroundColor: "#000",
                cursor: "pointer",
                color: "white",
              }}
              onClick={goBack}
            >
              点击跳转回Home 组件
            </div>
            关于页面About
          </div>
        );
      }
      
      // 非hash模式的路由,一般 可以放在index.js 中,直接包裹 App 组件也行的
      /* *
           * 
              const root = ReactDOM.createRoot(document.getElementById('root'));
              root.render(
                <<BrowserRouter>
                  <App />
                </BrowserRouter>
              );
           * */
      
      {
        /* 所有的路由配置均在 BrowserRouter 内部 */
      }
      function App() {
        return (
          <BrowserRouter>
            <div className="App">
              {/* 指定跳转的组件,to 用来配置路由地址 */}
              <Link to="/">首页</Link>
              <br />
              <Link to="/about">关于</Link>
              {/* 路由出口:路由对应的组件会在这里进行渲染, 同时这个 Routes 用来 替换曾经的 Switch */}
              <Routes>
                {/* 指定路由路径和组件的对应关系:path 代表路径,element 代表对应的组件,它们成对出现 */}
                <Route path="/" element={<Home />}></Route>
                <Route path="/about" element={<About />}></Route>
              </Routes>
            </div>
          </BrowserRouter>
        );
      }
      
      export default App;
      
  7. 导航方式

    1. 声明式导航
      1. 使用 <Link to="/">跳转</Link> 的方式是:声明式导航,或者 NavLink(相当于Link的加强版)方式
    2. 编程式导航
      1. 函数式组件
        function About() {
          // 用于函数式组件,用于类组件可能会报错
          const navigate = useNavigate();
          function goBack() {
            navigate("/");
          }
          return (
            <div>
              <div
                style={{
                  width: "200px",
                  height: "20px",
                  backgroundColor: "#000",
                  cursor: "pointer",
                  color: "white",
                }}
                onClick={goBack}
              >
                点击跳转回Home 组件
              </div>
            </div>
          );
        }
      2. 类组件中:

        由于react-router-dom升级到6版本后,无法按照this.props.history.push()进行编程式导航,此时props会提示是空值,v6文档里把路由组件默认接受的三个属性给移除了,官网文档里给出的解决方案是使用useNavigate()这个hook,但是hook只能存在于无状态组件,无法用在类组件中,通过Navigate这个标签来实现路由跳转,但官方其实也不推荐,更推荐去使用hook。

    3. 获取路由参数

      1. useParams 获取动态路由的值
      2. useSearchParams 获取查询字符串的值
      3. useLocation 获取上一个页面传递进来的 state 参数 v5、v6一样
    4. import { useEffect } from "react";
      import {
        BrowserRouter,
        Routes,
        Route,
        Link,
        useNavigate,
        useParams,
        useSearchParams,
        useLocation,
      } from "react-router-dom";
      
      function Home() {
        const navigate = useNavigate();
      
        // 动态路由
        function dynamicRoutes() {
          navigate(`/about/${1}/${2}`);
        }
      
        // useSearchParams 传递参数
        function searchPassParams() {
          navigate(`/about?id=1&search=2`);
        }
      
        // location 方式传递参数
        function locationRouts() {
          let obj = {
            a: 1,
            b: 2,
            c: 3,
          };
          navigate(`/about`, { state: obj });
       // 特点:
       // 1、BrowserRouter(history)模式下,刷新页面参数不消失,参数不会在地址栏显示,因为state保存在 history对象中
       // 2、HashRouter(hash)模式下,刷新页面参数消失!!!参数不会在地址栏显示
        }
      
        return (
          <div>
            <div onClick={dynamicRoutes}>动态路由方式 /about/:id/:key</div>
            <div onClick={searchPassParams}>search 方式传递参数</div>
            <div onClick={locationRouts}>location 方式传递参数</div>
            <p>首页组件Home</p>
          </div>
        );
      }
      
      function About() {
        const navigate = useNavigate();
        const params = useParams(); // 动态路由获取参数 { id: 1, key: 2} 具体看你怎么, 传一个也是可以的
        const [searchParams, setSearchParams] = useSearchParams();
        const location = useLocation();
      
        function goBack() {
          navigate("/");
        }
      
        // 动态路由传递参数
        useEffect(() => {
          console.log("/about/:id 动态路由", params);
        }, [params]);
      
        // searchParams 传递参数
        useEffect(() => {
          console.log(
            "searchParams 传递参数,查看 search 参数值",
            searchParams.get("search")
          );
          // setSearchParams; 用来设置 url 的 key 和 参数
          // setSearchParams("key=1");
        }, [searchParams]);
      
        // useLocation 接受参数
        useEffect(() => {
          console.log("obj 传递的参数", location.state);
        }, [location]);
      
        return (
          <div>
            <div
              style={{
                width: "200px",
                height: "20px",
                backgroundColor: "#000",
                cursor: "pointer",
                color: "white",
              }}
              onClick={goBack}
            >
              点击跳转回Home 组件
            </div>
            关于页面About
          </div>
        );
      }
      
      function App() {
        return (
          <BrowserRouter>
            <div className="App">
              <Link to="/">首页</Link>
              <br />
              <Link to="/about">关于</Link>
              <Routes>
                <Route path="/" element={<Home />}></Route>
                {/* 动态路由传递的方式, 和 Vue 大同小异 */}
                {/* <Route path="/about/:id/:key" element={<About />}></Route> */}
                {/* useSearchParams \ useLocation  传递参数*/}
                <Route path="/about" element={<About />}></Route>
              </Routes>
            </div>
          </BrowserRouter>
        );
      }
      
      export default App;
      
    • 总结
      • state传参:BrowserRouter(history)模式下,刷新页面不消失;而​​​​​
      • HashRouter(hash)模式下,刷新页面会消失,但都不会暴露在url中
      • params传参(动态路由):可读性高,便于维护,当另一个页面一定需要某数据时,推荐使用
      • search传参:会暴露在url中,刷新页面不会消失,但取数据时,需处理
  8. react-router-dom 路由嵌套

    • ​​​​​​​嵌套路由的 path 可以不用写父级,会直接拼接;
    • 由于 /about/Aboutdetail 的匹配度大于 /about/* ,所以输入精确地址,会精确匹配,而不是匹配到动态路由;
    • 嵌套路由必须在父级追加 Outlet 组件,作为子级组件的占位符,类似于 vue-router 中的 router-view 。
    • 实例代码
      import { useEffect } from "react";
      import {
        BrowserRouter,
        Routes,
        Route,
        Link,
        useNavigate,
        Outlet,
      } from "react-router-dom";
      
      function Home() {
        return (
          <div>
            <p>首页组件Home</p>
          </div>
        );
      }
      
      function About() {
        const naviate = useNavigate();
        function goAboutdetail() {
          naviate("/about/aboutDetail");
        }
        return (
          <div>
            <div>关于页面About</div>
            <div onClick={goAboutdetail}>点击跳转到到 Aboutdetail 组件 </div>
            <Outlet></Outlet>
          </div>
        );
      }
      
      function Aboutdetail() {
        return <div>Aboutdetail 子页面</div>;
      }
      
      function App() {
        return (
          <BrowserRouter>
            <div className="App">
              <Link to="/">首页</Link>
              <br />
              <Link to="/about">关于</Link>
              <Routes>
                <Route path="/" element={<Home />}></Route>
                <Route path="/about" element={<About />}>
                  <Route path="aboutDetail" element={<Aboutdetail />}></Route>
                </Route>
              </Routes>
            </div>
          </BrowserRouter>
        );
      }
      
      export default App;
      
      ​​​​​
  9. react-router-dom 使用 useRoutes API 对路由进行集中式管理

    • ​​​​​​​
      import { lazy } from "react";
      import {
        Link,
        useNavigate,
        useRoutes,
        Outlet,
        Navigate,
      } from "react-router-dom";
      
      function Home() {
        return (
          <div>
            <p>首页组件Home</p>
          </div>
        );
      }
      
      function About() {
        const naviate = useNavigate();
      
        function goAboutdetail() {
          naviate("/about/aboutDetail");
        }
      
        return (
          <div>
            <div>关于页面About</div>
            <div onClick={goAboutdetail}>点击跳转到到 Aboutdetail 组件 </div>
            <Outlet></Outlet>
          </div>
        );
      }
      
      function Aboutdetail() {
        return <div>Aboutdetail 子页面</div>;
      }
      
      function Detail() {
        return <div>About 子页面</div>;
      }
      
      const routes = [
        {
          path: "/",
          element: <Navigate to={"/home"} />,
        },
        {
          path: "/home",
          element:  <Home></Home>,
        },
        {
          path: "/about",
          element: <About />,
          children: [
            {
              index: true,
              path: "aboutDetail",
              element: <Aboutdetail />,
            },
            {
              path: "detail",
              element: <Detail />,
            },
          ],
        },
      ];
      
      function App() {
        return (
          <div>
            <div className="App">
              <Link to="/">首页</Link>
              <br />
              <Link to="/about">关于</Link>
            </div>
            {useRoutes(routes)}
          </div>
        );
      }
      
      export default App;
      
      ​​​​​​​
    • 设置默认二级路由设置需要注意的地方,
      • 场景:需要默认显示二级路由,这时候需要默认二级路由设置

        方法:添加index属性,再把他自己的path干掉

      • <Route index element={<detail/>}></Route>
        
        ​​​​​​​
      • 同样的,useRoutes 中集中管理路由也把 path 去掉,就可以实现 默认显示的组件
         
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清云随笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值