ReactRouter6


# 概述

  • React Router 以三个不同的包发布到 npm 上,它们分别为:

    • react-router:路由的核心库,提供了很多的:组件,钩子
    • react-router-dom:包含 react-router 所有内容,并添加一些专门用于 DOM 的组件,例如 <BrowserRouter> 等
    • react-router-native:包含 react-router 所有内容,并添加
      一些专门用于 ReactNative 的 API,例如 <NativeRouter> 等
  • 与 React Router 5.x 版本相比,改变了什么?

    • 内置组件的变化:移除 <Switch/> ,新增 <Routes/> 等
    • 语法的变化: component={About} 变为 element={<About/>} 等
    • 新增多个 Hook: useParams , useNavigate , useMatch 等
    • 官方明确推荐函数式组件了
    • …
  • npm i react-router-dom

# Component

# 一级案例

  • App.jsx

    import React from "react";
    import {NavLink,Routes,Route} from "react-router-dom"
    import About from "./pages/About"
    import Home from "./pages/Home"
    
    export default function App() {
      return (
        <div>
          <h1>React Router Demo</h1>
          //路由链接
          <NavLink to='/about'>About</NavLink>
          <NavLink to='/home'>Home</NavLink>
    
          //注册组件
          //React Route6 中 switch 改为了 Routes
          <Routes>
            <Route path='/about' element={<About/>} />
            <Route path='/home' element={<Home/>} />
          </Routes>
        </div>;
      )
    }
  • index.jsx

    import React from "react";
    import ReactDom from "react-dom";
    import { BrowserRouter } from "react-router-dom";
    import App from "./App";
    
    ReactDom.render(
      <BrowserRouter>
        <App />
      </BrowserRouter>,
      document.getElementById("root")
    );
  • pages 文件夹 —>About.jsx

    import React from "react";
    export default function About() {
      return <h1>我是About的内容</h1>;
    }
  • pages 文件夹 —>Home.jsx

    import React from "react";
    export default function Home() {
      return <h1>我是Home的内容</h1>;
    }

# 1. <BrowserRouter>

  • 说明: <BrowserRouter> 用于包裹整个应用

  • 实例代码:

    import React from "react";
    import ReactDom from "react-dom";
    import { BrowserRouter } from "react-router-dom";
    
    ReactDom.render(
      <BrowserRouter>
        //整体结构,通常为App组件
      </BrowserRouter>,
      document.getElementById("root")

# 2. <HashRouter>

  • 说明:作用与 <BrowserRouter> 一样,但 <HashRouter> 修改的是地址栏的 hash 值
  • 备注:6.x 版本中 <HashRouter> 和 <BrowserRouter> 的用法与 5.x 相同

# 3. <Routes> 与 <Route>

  • v6 版本中移出了先前的 <Switch> ,引入了新的替代者: <Routes>

  • <Routes> 和 <Route> 要配合使用,且必须要用 <Routes> 包裹 <Route>

  • <Route> 相当于一个 if 语句,如果其路径与当前 URL 匹配,则呈现其对应的组件

  • <Route cassSensitive> 属性用于指定:匹配时是否区分大小写 (默认为 false)

  • 当 URL 发生变化时, <Routes> 都会查看其所有子 <Route> 元素以找到最佳匹配并呈现组件

  • <Route> 也可以嵌套使用,且可配合 useRoutes() 配置’路由表’,但需要通过路由表 <Outlet> 组件来渲染其子路由

  • 示例代码:

    <Routes>
      //path属性用与定义路径,element属性用于定义当前路径所对应的组件
      <Route path="/login" element={<Login />}></Route>
      //用于定义嵌套路由,home是一级路由,对应的路径是/home
      <Route path="home" element={<Home />}>
        //test1和test2是二级路由,对应的路径是/home/test1 或 /home/test2
        <Route path="test1" element={<Test />}></Route>
        <Route path="test1" element={<Test2 />}></Route>
      </Route>
      //Route也可以不写element属性,这时就是用于展示嵌套的路由,所对应的路径是/users/xxx
      <Route path="users">
        <Route path="xxx" element={<Demo />}></Route>
      </Route>
    </Routes>
  • 作用:修改 URL,且不发送网络请求 (路由链接)

  • 注意:外侧需要用 <BrowserRouter> 或 <HashRouter> 包裹

  • 实例代码:

    import { Link } from "react-router-dom";
    function Test() {
      return (
        <div>
          <Link to="路径">按钮</Link>
        </div>
      );
    }
  • NavLink 自定义高亮类名案例
    注意:NavLink 默认类名是 active,下面是指定自定义的 class

    <NavLink
      className={({ isActive }) => (isActive ? "base 自定义active类名" : "base ")}
    />;
    
    //或者
    function xxName({ isActive }) {
      return isActive ? "base 自定义active类名" : "base ";
    }

# 6. <Navigate>

  • 作用:只要 <Navigate> 组件被渲染,就会修改路径,切换视图

  • replace 属性用于控制跳转模式 (push 或 replace,默认是 push)

  • 示例代码: pages 文件夹 —>Home.jsx

    import React, { useState } from "react";
    import { Navigate } from "react-router-dom";
    export default function Home() {
      const [sum, setSum] = useState(1);
      return (
        <div>
          <h1>我是Home的内容</h1>
          //根据sum的值决定是否切换视图
          {sum === 2 ? (
            <Navigate to="about" replace={true} />
          ) : (
            <h2>当前sum的值是:{sum}</h2>
          )}
          //Navigate 只要渲染,就会引起视图的切换 //replace不会留下痕迹
          <button
            onClick={() => {
              setSum(2);
            }}
          >
            点我将sum变为2
          </button>
        </div>
      );
    }
  • 示例代码: App.jsx

    import React from "react";
    import {NavLink,Routes,Route,Navigate} from "react-router-dom"
    import About from "./pages/About"
    import Home from "./pages/Home"
    
    export default function App() {
      return (
        <div>
          <h1>React Router Demo</h1>
          //路由链接
          <NavLink to='/about'>About</NavLink>
          <NavLink to='/home'>Home</NavLink>
    
          //注册组件
          //React Route6 中 switch 改为了 Routes
          <Routes>
            <Route path='/about' element={<About/>} />
            <Route path='/home' element={<Home/>} />
            // 一渲染视图就切换
            <Route path='' element={<Navigate to='/about'/>}>
          </Routes>
        </div>;
      )
    }

# 7. <Outlet>

  • src 文件夹 ->routes 文件夹 ->index.js

    import About from "./pages/About";
    import Home from "./pages/Home";
    import Message from "./pages/Message";
    import News from "./pages/News";
    import { Navigate } from "react-router-dom";
    
    export default {
      {
        path:"/about",
        element:<About/>
      },
      {
        path:"/home",
        element:<Home/>,
        children:[
          {
            //这里不用写/
            path:"news",
            element:<News/>,
          },
          {
            path:"message",
            element:<Message/>,
          }
        ]
      },
      {
        path:"/",
        element:<Navigate to="/about"/>
      },
    }
  • App.jsx

    import React from "react";
    import {NavLink,useRoutes} from "react-router-dom"
    import routes from "./routes"
    
    export default function App() {
      //根据路由表生成对应的路由规则
      const element = useRoutes(routes)
      return (
        <div>
          <h1>React Router Demo</h1>
          //路由链接
          <NavLink to='/about'>About</NavLink>
          //end就是:如果我的子级路由匹配了,那我自己本身会失去高亮
          //默认情况下,当Home的子组件匹配成功,Home的导航也会高亮
          //当NavLink上添加了end属性后,若Home的子组件匹配成功,则Home的导航没有高亮效果
          <NavLink end to='/home'>Home</NavLink>
    
          //注册组件
          {element}
        </div>;
      )
    }
  • pages 文件夹 —>About.jsx

    import React from "react";
    export default function About() {
      return (
        <div>
          <h1>我是About的内容</h1>
        </div>
      );
    }
  • pages 文件夹 —>Home.jsx

    import React from "react";
    import { NavLink, Outlet } from "react-router-dom";
    export default function Home() {
      return (
        <div>
          <h1>我是Home的内容</h1>
          //这里直接写news,不带/表示:之前那一堆都带着的路径/news,比如说它的父级是home那这里的路径就是/home/news
          <NavLink to="news">news</NavLink>
          <NavLink to="message">message</NavLink>
          // 指定路由组件呈现的位置
          <Outlet />
        </div>
      );
    }
  • pages 文件夹 —>News.jsx

    import React from "react";
    export default function News() {
      return <h1>我是News的内容</h1>;
    }
  • pages 文件夹 —>Message.jsx

    import React from "react";
    export default function Message() {
      return <h1>我是Message的内容</h1>;
    }

# Hooks

# 1.useRoutes()

  • src 文件夹 ->routes 文件夹 ->index.js

    import About from "./pages/About";
    import Home from "./pages/Home";
    import { Navigate } from "react-router-dom";
    
    export default {
      {
        path:"/about",
        element:<About/>
      },
      {
        path:"/home",
        element:<Home/>
      },
      {
        path:"/",
        element:<Navigate to="/about"/>
      },
    }
  • App.jsx

    import React from "react";
    import {NavLink,useRoutes} from "react-router-dom"
    import routes from "./routes"
    
    export default function App() {
      //根据路由表生成对应的路由规则
      const element = useRoutes(routes)
      return (
        <div>
          <h1>React Router Demo</h1>
          //路由链接
          <NavLink to='/about'>About</NavLink>
          <NavLink to='/home'>Home</NavLink>
    
          //注册组件
          {element}
        </div>;
      )
    }

# 2. 路由的 params 参数:useParams ()

  • src 文件夹 ->routes 文件夹 ->index.js

    import About from "./pages/About";
    import Home from "./pages/Home";
    import Message from "./pages/Message";
    import News from "./pages/News";
    import Detail from "./pages/News";
    
    import { Navigate } from "react-router-dom";
    
    export default {
      {
        path:"/about",
        element:<About/>
      },
      {
        path:"/home",
        element:<Home/>,
        children:[
          {
            //这里不用写/
            path:"news",
            element:<News/>,
          },
          {
            path:"message",
            element:<Message/>,
            children:[
              {
                path:"detail/:id/:title/:content",
                element:<Detail/>,
              },
            ]
          }
        ]
      },
    }
  • pages 文件夹 —>Message.jsx

    import React, { useState } from "react";
    import { Link, Outlet } from "react-router-dom";
    export default function Message() {
      const [message] = useState([
        { id: "001", title: "标题1", content: "锄禾日当午1" },
        { id: "002", title: "标题2", content: "锄禾日当午2" },
        { id: "003", title: "标题3", content: "锄禾日当午3" },
        { id: "004", title: "标题4", content: "锄禾日当午4" },
      ]);
      return (
        <div>
          <h1>我是Message的内容</h1>
          <ul>
            {message.map((ele) => {
              return (
                //路由链接
                <li key={ele.id}>
                  <Link to={`detail/${ele.id}/${ele.title}/${ele.content}`}>
                    {ele.title}
                  </Link>
                </li>
              );
            })}
          </ul>
          //指定路由组件的展示位置
          <Outlet />
        </div>
      );
    }
  • pages 文件夹 —>Detail.jsx

    import React, { useState } from "react";
    import { useParams } from "react-router-dom";
    export default function Message() {
      //这样可以获取到params参数
      const { id, title, content } = useParams();
      return (
        <div>
          <h1>我是Message的内容</h1>
          <ul>
            <li>{id}</li>
            <li>{title}</li>
            <li>{content}</li>
          </ul>
        </div>
      );
    }

# 3. 路由的 search 参数:useSearchParams ()

  • src 文件夹 ->routes 文件夹 ->index.js

    import About from "./pages/About";
    import Home from "./pages/Home";
    import Message from "./pages/Message";
    import News from "./pages/News";
    import Detail from "./pages/News";
    
    import { Navigate } from "react-router-dom";
    
    export default {
      {
        path:"/about",
        element:<About/>
      },
      {
        path:"/home",
        element:<Home/>,
        children:[
          {
            //这里不用写/
            path:"news",
            element:<News/>,
          },
          {
            path:"message",
            element:<Message/>,
            children:[
              {
                // search参数这里不用加
                path:"detail",
                element:<Detail/>,
              },
            ]
          }
        ]
      },
    }
  • pages 文件夹 —>Message.jsx

    import React, { useState } from "react";
    import { Link, Outlet } from "react-router-dom";
    export default function Message() {
      const [message] = useState([
        { id: "001", title: "标题1", content: "锄禾日当午1" },
        { id: "002", title: "标题2", content: "锄禾日当午2" },
        { id: "003", title: "标题3", content: "锄禾日当午3" },
        { id: "004", title: "标题4", content: "锄禾日当午4" },
      ]);
      return (
        <div>
          <h1>我是Message的内容</h1>
          <ul>
            {message.map((ele) => {
              return (
                //路由链接
                <li key={ele.id}>
                  <Link
                    to={`detail?id=${ele.id}&title=${ele.title}&content=${ele.content}`}
                  >
                    {ele.title}
                  </Link>
                </li>
              );
            })}
          </ul>
          //指定路由组件的展示位置
          <Outlet />
        </div>
      );
    }
  • pages 文件夹 —>Detail.jsx

    import React, { useState } from "react";
    import { useSearchParams } from "react-router-dom";
    export default function Message() {
      //这样可以获取到search参数
      const [search, setSearch] = useSearchParams();
      const id = search.get("id");
      const title = search.get("title");
      const content = search.get("content");
    
      return (
        <div>
          <button @click= {()=>setSearch('id=008&title=hhh&content=嘻嘻嘻')}>点我更新search参数</button>
          <ul>
            <li>{id}</li>
            <li>{title}</li>
            <li>{content}</li>
          </ul>
        </div>
      );
    }

# 4. 路由的 state 参数:useLocation ()

  • src 文件夹 ->routes 文件夹 ->index.js

    import About from "./pages/About";
    import Home from "./pages/Home";
    import Message from "./pages/Message";
    import News from "./pages/News";
    import Detail from "./pages/News";
    import { Navigate } from "react-router-dom";
    
    export default {
      {
        path:"/about",
        element:<About/>
      },
      {
        path:"/home",
        element:<Home/>,
        children:[
          {
            //这里不用写/
            path:"news",
            element:<News/>,
          },
          {
            path:"message",
            element:<Message/>,
            children:[
              {
                // state参数这里不用加
                path:"detail",
                element:<Detail/>,
              },
            ]
          }
        ]
      },
    }
  • pages 文件夹 —>Message.jsx

    import React, { useState } from "react";
    import { Link, Outlet } from "react-router-dom";
    export default function Message() {
      const [message] = useState([
        { id: "001", title: "标题1", content: "锄禾日当午1" },
        { id: "002", title: "标题2", content: "锄禾日当午2" },
        { id: "003", title: "标题3", content: "锄禾日当午3" },
        { id: "004", title: "标题4", content: "锄禾日当午4" },
      ]);
      return (
        <div>
          <h1>我是Message的内容</h1>
          <ul>
            {message.map((ele) => {
              return (
                //路由链接
                <li key={ele.id}>
                  <Link
                    to="detail"
                    state={{
                      id: ele.id,
                      title: ele.title,
                      content: ele.content,
                    }}
                  >
                    {ele.title}
                  </Link>
                </li>
              );
            })}
          </ul>
          //指定路由组件的展示位置
          <Outlet />
        </div>
      );
    }
  • pages 文件夹 —>Detail.jsx

    import React, { useState } from "react";
    import { useLocation } from "react-router-dom";
    export default function Message() {
      const {
        state: { id, title, content },
      } = useLocation();
      return (
        <div>
          <ul>
            <li>{id}</li>
            <li>{title}</li>
            <li>{content}</li>
          </ul>
        </div>
      );
    }

# 5. 编程式路由导航:useNavigate ()

  • pages 文件夹 —>Message.jsx

    import React, { useState } from "react";
    import { Link, Outlet, useNavigate } from "react-router-dom";
    export default function Message() {
      const [message] = useState([
        { id: "001", title: "标题1", content: "锄禾日当午1" },
        { id: "002", title: "标题2", content: "锄禾日当午2" },
        { id: "003", title: "标题3", content: "锄禾日当午3" },
        { id: "004", title: "标题4", content: "锄禾日当午4" },
      ]);
      const navigate = useNavigate();
      function showDetail(ele) {
        navigate("detail", {
          replace: false,
          state: {
            id: ele.id,
            title: ele.title,
            content: ele.content,
          },
        });
      }
      return (
        <div>
          <h1>我是Message的内容</h1>
          <ul>
            {message.map((ele) => {
              return (
                //路由链接
                <li key={ele.id}>
                  <Link
                    to="detail"
                    state={{
                      id: ele.id,
                      title: ele.title,
                      content: ele.content,
                    }}
                  >
                    {ele.title}
                  </Link>
                  <button onClick={() => showDetail(ele)}>查看详情</button>
                </li>
              );
            })}
          </ul>
          //指定路由组件的展示位置
          <Outlet />
        </div>
      );
    }
  • components 文件夹 ->Header.jsx

    import React from "react";
    import {useNavigate} from "react-router-dom"
    export default function Header() {
      const navigate = useNavigate()
      function back(){
        navigate(-1 )
      }
      function forward(){
        navigate(1)
      }
    
      return (
        <div>
          <h1>React Router Demo</h1>
          <button onClick={()=>back}><- 后退</button>
          <button onClick={()=>forward}>前进 -></button>
        </div>;
      )
    }
  • App.jsx

    import React from "react";
    import {NavLink,useRoutes} from "react-router-dom"
    import routes from "./routes"
    import Header from "./components/header"
    
    export default function App() {
      //根据路由表生成对应的路由规则
      const element = useRoutes(routes)
      return (
        <div>
          <Header/>
          //路由链接
          <NavLink to='/about'>About</NavLink>
          <NavLink to='/home'>Home</NavLink>
    
          //注册组件
          {element}
        </div>;
      )
    }

# 6.useMatch()

  • 作用:返回当前匹配信息,对应 5.x 中的路由组件的 match 属性

  • 代码示例

    <NavLink to="/login/1/10">登录</NavLink>;
    const match = useMatch("/login/:x/:y");
    console.log(match);
    //输出内容如下:
    {
      params: {x: "1",y:"10"},
      pathname:'/login/1/10',
      pathnameBase:'/login/1/10',
      pattern:{
        path:"/login/:x/:y",
        caseSensitive:false,
        end:false
      }
    }

# 7.useInRouterContext()

作用:如果组件在 <Router> 的上下文中呈现,则 useInRouterContext 钩子返回 true,否则返回 false。
其实就是只要被 <BrowserRouter> 包裹的返回的都是 true

# 8.useNavigationType()

  • 作用:返回当前的导航类型 (用户是如何来到当前页面的)
  • 返回值: POP , PUSH , REPLACE ,代表的是你通过哪种方式来到这个路由组件的
  • 备注: POP 是指在浏览器中直接打开了这个路由组件 (刷新页面)

# 9.useOutlet()

  • 作用:用来呈现当前组件中渲染的嵌套路由

  • 示例代码:

    const result = useOutlet();
    console.log(result);
    //如果嵌套路由没有挂载,则result为null
    //如果嵌套路由已经挂载,则展示嵌套的路由对象,可以通过这个对象拿到很多东西,比如:props,ref等

# 10.useResolvedPath()

  • 作用:给定一个 URL 值,解析其中的:path,search,hash 值

  • 代码实例:

    import { useResolvedPath } from "react-router-dom";
    console.log(useResolvedPath("/users?id=001&name=tom#qwe));
    // 返回:{pathname:'/user',search:'?id=001&name=tom',hash:"#qwe"}

文章作者: Mrr-cxh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mrr-cxh !
赏
 上一篇
Kwai一些解决方案 Kwai一些解决方案
本文是博主在某大厂实习所遇到问题的一些解决方案,并无涉及公司隐私。只是一些小知识点的总结或者解决方案。
2022-06-19
下一篇 
React 4.0 React 4.0
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
2022-05-15
  目录