07-React Router6

81 阅读8分钟

React Router 6

1.<BrowserRouter>
    1.说明:<BrowserRouter>用于包裹整个应用.
    2.示例代码:
        import React from "react";
        import ReactDOM from "react-dom";
        import { BrowserRouter } from "react-router-dom";
        ReactDOM.render(
            <BrowserRouter>
                {/_ 整体结构 (通常为 App 组件) _/}
            </BrowserRouter>,
        root)

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

3.<Routes/> 与 <Route/>
    1.v6 版本中移出了先前的<Switch>,引入了新的替代者: <Routes>.
    2.<Routes>和 <Route>要配合使用,且必须要用<Routes>包裹<Route>.
    3.<Route>相当于一个 if 语句,如果其路径与当前 URL 匹配,则呈现其对应的组件
    4.<Route caseSensitive> 属性用于指定: 匹配时是否区分大小写 (默认为 false).
    5.当 URL 发生变化时,<Routes>都会查看其所有子<Route> 元素以找到最佳匹配并呈现组件
    6.<Route>也可以嵌套使用,且可配合 useRoutes() 配置"路由表",但需要通过<outlet>组件来渲染其子路由.
    7. 示例代码
    <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="test2" element={<Test2/>}></Route>
        </Route>
        //Route也可以不写element届性,这时就是用于展示嵌套的路由.所对应的路径是/users/xxx
        <Route path="users">
            <Route path="xxx" element={<Demo />} />
        </Route>
    </Routes>


4. <Link>
    1.作用: 修改URL,且不发送网络请求 (路由链接)
    2.注意:外侧需要用<BrowserRouter>或<HashRouter>包裹
    3. 示例代码:
        import { Link } from "react-router-dom";
        function Test() {
            return (
                <div>
                    <Link to="/路径">按钮</Link>
                </div>
            )
        }


5. <NavLink>
    1.作用: 与<Link>组件类似,且可实现导航的"高亮"效果
    2. 示例代码:
        // 注意: NavLink默认类名是active,下面是指定自定义的class
        //自定义样式
        <NavLink
            to="login"
            className={({ isActive }) => {
                console.log('home',isActive)
                return isActive ? 'base one' :'base'
            >login</NavLink>

        // 默认情况下,当Home的子组件匹配成功,Home的导航也会高亮,
        // 当NavLink上添加了end属性后,若Home的子组件匹配成功,则Home的导航没有高亮效果
        <NavLink to="home" end >home</NavLink>


6. <Navigate>
    1.作用:只要<Navigate>组件被染,就会修改路径,切换视图.
    2.replace 属性用于控制跳转模式 (push 或 replace,默认是push).
    3.示例代码:
        import React,fuseStater from 'react!
        import {Navigate} from 'react-router-dom!
        export default function Home() {
            const [sum,setSum] = useState(1)
            return (
                <div>
                    <h3>我是Home的内容</h3>
                    // 根据sum的值决定是否切换视图
                    {sum === 1 ?<h4>sum的值为{sum}</h4> : <Navigate to="/about" replace={true}/>}
                    <button onClick={()=>setSum(2)}>点我将sum变为2</button>
                </div>
                )
        }


6. <Outlet>
1. useRoutes()

2. useNavigate()

3. useParams()

4. useSearchParams()

5. useLocation()

6. useMatch()

7. uselnRouterContext()

8. useNavigationType()
    1.作用: 返回当前的导航类型 (用户是如何来到当前页面的)
    2.返回值: POPPUSHREPLACE
    3.备注: PoP 是指在浏览器中直接打开了这个路由组件 (刷新页面)
9. useOutlet()
    1.作用: 用来呈现当前组件中渲染的嵌套路由
    2.示例代码:
        const result = useOutlet()
        console.log(result)
        // 如果嵌套路由没有挂载,则result为nu11
        // 如果嵌套路由已经挂载,则展示嵌套的路由对象
10. useResolvedPath()
    1.作用: 给定一个 URL值,解析其中的: path、search、hash值.

01-一级路由

//创建外壳组件APP
import React, { Component } from "react";
import { NavLink, Route, Routes, Navigate, useRoutes } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import routers from "./routers";
export default function App() {
  return (
    <div>
      <h1>我是APP</h1>
      {/* 注册跳转标签 */}
      <NavLink to="/about">About</NavLink>
      <NavLink to="/home">Home</NavLink>
      {/* 注册路由 普通写法 */}
      {/* 之前 Switch 现在是 Routes */}

      <Routes>
        {/* 之前是 Component 现在是 element */}
        {/* 现在 path 是大小写都可以了 about ABOUT 是一样的 都会被解析成小写 */}
        <Route path="/about" element={<About />} />
        <Route path="/home" element={<Home />} />

        {/* Routes 和之前一样,一个匹配上后就不会去匹配别的了 */}
        <Route path="/home" element={<Demo />} />
      </Routes>
    </div>
  );
}

02-Navigate 重定向

//创建外壳组件APP
import React, { Component } from "react";
import { NavLink, Route, Routes, Navigate, useRoutes } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
export default function App() {
  return (
    <div>
      <h1>我是APP</h1>
      {/* 注册跳转标签 */}
      <NavLink to="/about">About</NavLink>
      <NavLink to="/home">Home</NavLink>
      {/* 注册路由 普通写法 */}
      {/* 之前 Switch 现在是 Routes */}

      <Routes>
        {/* 之前是 Component 现在是 element */}
        {/* 现在 path 是大小写都可以了 about ABOUT 是一样的 都会被解析成小写 */}
        <Route path="/about" element={<About />} />
        <Route path="/home" element={<Home />} />

        {/* Routes 和之前一样,一个匹配上后就不会去匹配别的了 */}
        <Route path="/home" element={<Demo />} />

        {/* Navigate 和之前的 redirect 效果一样,写法不一样 */}
        <Route path="/" element={<Navigate to="/about" />} />
      </Routes>
    </div>
  );
}
import React, { Component, useState } from "react";
import { Navigate } from "react-router-dom";
export default function Home() {
  const [sum, setSum] = useState(0);
  return (
    <div style={{ padding: "10px" }}>
      <div style={{ border: "1px solid red" }}>
        <h2>导航区</h2>
        <div>
          <a style={{ float: "left", marginRight: "10px" }}>About</a>
          <a style={{ color: "red" }}>Home</a>
        </div>
      </div>
      <div style={{ border: "1px solid green", marginTop: "10px" }}>
        <h2>展示区</h2>
        <h2>Home</h2>

        {/* 这样样式一个 Navigate 的使用方法 */}
        {/* Navigate 只要渲染就会引起页面的切换 */}
        {sum === 2 ? (
          <Navigate to="/about" replace />
        ) : (
          <h4>当前的sum的值为{sum}</h4>
        )}
        <button onClick={() => setSum(2)}>点击改变sum的值</button>
      </div>
    </div>
  );
}

03-NavLink 高亮

//创建外壳组件APP
import React, { Component } from "react";
import { NavLink, Route, Routes, Navigate, useRoutes } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
export default function App() {
  return (
    <div>
      <h1>我是APP</h1>
      {/* 注册跳转标签 */}
      {/* 之前是 activeClassName 现在是 className 返回一个函数 */}
      <NavLink
        className={({ isActive }) => (isActive ? "lgqactive" : "aaa")}
        to="/about"
      >
        About
      </NavLink>
      <NavLink
        className={({ isActive }) => (isActive ? "lgqactive" : "aaa")}
        to="/home"
      >
        Home
      </NavLink>
      {/* 注册路由 普通写法 */}
      {/* 之前 Switch 现在是 Routes */}

      <Routes>
        {/* 之前是 Component 现在是 element */}
        {/* 现在 path 是大小写都可以了 about ABOUT 是一样的 都会被解析成小写 */}
        <Route path="/about" element={<About />} />
        <Route path="/home" element={<Home />} />
      </Routes>
    </div>
  );
}

04-useRoutes 路由表

04-useRoutes 路由表\App.jsx

//创建外壳组件APP
import React, { Component } from "react";
import { NavLink, useRoutes } from "react-router-dom";

import routers from "./routers";
export default function App() {
  // 这个就是路由表,来生成路由
  const element = useRoutes(routers);
  return (
    <div>
      <h1>我是APP</h1>
      {/* 注册跳转标签 */}
      {/* 之前是 activeClassName 现在是 className 返回一个函数 */}
      <NavLink to="/about">About</NavLink>
      <NavLink to="/home">Home</NavLink>

      {/* 路由表写法 */}
      {element}
    </div>
  );
}

04-useRoutes 路由表\routers\index.js

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

05-Outlet 组件展示位置

import React, { Component, useState } from "react";
import { NavLink, Outlet } from "react-router-dom";

export default function Home() {
  return (
    <div style={{ padding: "10px" }}>
      <div style={{ border: "1px solid red" }}>
        <h2>导航区</h2>
        <div>
          <a style={{ float: "left", marginRight: "10px" }}>About</a>
          <a style={{ color: "red" }}>Home</a>
        </div>
      </div>
      <div style={{ border: "1px solid green", marginTop: "10px" }}>
        <h2>展示区</h2>
        <h2>Home</h2>
        <NavLink
          to="message"
          className={({ isActive }) => (isActive ? "lgqactive" : "")}
        >
          Message
        </NavLink>
        <NavLink
          to="news"
          className={({ isActive }) => (isActive ? "lgqactive" : "")}
        >
          News
        </NavLink>
        {/* 指定路由组件呈现的位置, 类似Vue的 route-view */}
        <Outlet />
      </div>
    </div>
  );
}

06-路由的 params 参数

06-路由的 params 参数\routers\index.js
import { Navigate } from "react-router-dom";
import About from "../pages/About";
import Home from "../pages/Home";
import Message from "../pages/Home/Message";
import News from "../pages/Home/News";
import Detail from "../pages/Home/Message/Detail";
export default [
  {
    path: "/about",
    element: <About />,
  },
  {
    path: "/home",
    element: <Home />,
    children: [
      {
        path: "message",
        element: <Message />,
        children: [
          {
            path: "detail/:id/:title/:content", // 路由 params 参数
            element: <Detail />,
          },
        ],
      },
      {
        path: "news",
        element: <News />,
      },
    ],
  },
  {
    path: "/",
    element: <Navigate to="/about" />,
  },
];
06-路由的 params 参数\pages\Home\Message\index.jsx
import React, { Component, useState } from "react";
import { Link, NavLink, Outlet } from "react-router-dom";

export default function Message() {
  const [message] = useState([
    { id: 1, title: "消息1", content: "内容1" },
    { id: 2, title: "消息2", content: "内容2" },
    { id: 3, title: "消息3", content: "内容3" },
    { id: 4, title: "消息4", content: "内容4" },
  ]);
  return (
    <div>
      <ul>
        {message.map((el) => {
          return (
            <li key={el.id}>
              {/* 路由 params 参数 */}
              <Link to={`detail/${el.id}/${el.title}/${el.content}`}>
                {el.title}
              </Link>
            </li>
          );
        })}
      </ul>
      <hr />
      {/* 指定 Detail 的展示位置 */}
      <Outlet />
    </div>
  );
}
06-路由的 params 参数\pages\Home\Message\Detail\index.jsx
import React from "react";
import { useParams } from "react-router-dom";
export default function Detail() {
  // 接收 params 参数
  const { id, title, content } = useParams();
  const _history = useMatch("/home/message/detail/:id/:title/:content");
  // 这个 _history 就是我们之前 Router5 的时候可以拿到的东西
  return (
    <div>
      <span>{id}</span> -<span>{title}</span> -<span>{content}</span>
    </div>
  );
}

07-路由的 search 参数

07-路由的 search 参数\routers\index.js

import { Navigate } from "react-router-dom";
import About from "../pages/About";
import Home from "../pages/Home";
import Message from "../pages/Home/Message";
import News from "../pages/Home/News";
import Detail from "../pages/Home/Message/Detail";
export default [
  {
    path: "/about",
    element: <About />,
  },
  {
    path: "/home",
    element: <Home />,
    children: [
      {
        path: "message",
        element: <Message />,
        children: [
          {
            path: "detail", // 路由 search 参数
            element: <Detail />,
          },
        ],
      },
      {
        path: "news",
        element: <News />,
      },
    ],
  },
  {
    path: "/",
    element: <Navigate to="/about" />,
  },
];

07-路由的 search 参数\pages\Home\Message\index.jsx

import React, { Component, useState } from "react";
import { Link, NavLink, Outlet } from "react-router-dom";

export default function Message() {
  const [message] = useState([
    { id: 1, title: "消息1", content: "内容1" },
    { id: 2, title: "消息2", content: "内容2" },
    { id: 3, title: "消息3", content: "内容3" },
    { id: 4, title: "消息4", content: "内容4" },
  ]);
  return (
    <div>
      <ul>
        {message.map((el) => {
          return (
            <li key={el.id}>
              {/* 路由 search 参数 */}
              <Link
                to={`detail?id=${el.id}&title=${el.title}&content=${el.content}&`}
              >
                {el.title}
              </Link>
            </li>
          );
        })}
      </ul>
      <hr />
      {/* 指定 Detail 的展示位置 */}
      <Outlet />
    </div>
  );
}

07-路由的 search 参数\pages\Home\Message\Detail\index.jsx

import React from "react";
import { useLocation, useSearchParams } from "react-router-dom";
export default function Detail() {
  // 接收 search 参数
  const [search, setSearch] = useSearchParams();
  const id = search.get("id");
  const title = search.get("title");
  const content = search.get("content");
  const _history = useLocation();
  console.log(_history);
  return (
    <div>
      <button onClick={() => setSearch("id=123&title=123&content=123")}>
        点我更新收到的 search 参数
      </button>
      <span>{id}</span> -<span>{title}</span> -<span>{content}</span>
    </div>
  );
}

08-路由的 state 参数

08-路由的 state 参数\routers\index.js

import { Navigate } from "react-router-dom";
import About from "../pages/About";
import Home from "../pages/Home";
import Message from "../pages/Home/Message";
import News from "../pages/Home/News";
import Detail from "../pages/Home/Message/Detail";
export default [
  {
    path: "/about",
    element: <About />,
  },
  {
    path: "/home",
    element: <Home />,
    children: [
      {
        path: "message",
        element: <Message />,
        children: [
          {
            path: "detail", // 路由 state 参数
            element: <Detail />,
          },
        ],
      },
      {
        path: "news",
        element: <News />,
      },
    ],
  },
  {
    path: "/",
    element: <Navigate to="/about" />,
  },
];

08-路由的 state 参数\pages\Home\Message\index.jsx

import React, { Component, useState } from "react";
import { Link, NavLink, Outlet } from "react-router-dom";

export default function Message() {
  const [message] = useState([
    { id: 1, title: "消息1", content: "内容1" },
    { id: 2, title: "消息2", content: "内容2" },
    { id: 3, title: "消息3", content: "内容3" },
    { id: 4, title: "消息4", content: "内容4" },
  ]);
  return (
    <div>
      <ul>
        {message.map((el) => {
          return (
            <li key={el.id}>
              {/* 路由 search 参数 */}
              <Link
                to="detail"
                state={{
                  ...el,
                }}
              >
                {el.title}
              </Link>
            </li>
          );
        })}
      </ul>
      <hr />
      {/* 指定 Detail 的展示位置 */}
      <Outlet />
    </div>
  );
}

08-路由的 state 参数\pages\Home\Message\Detail\index.jsx

import React from "react";
import { useLocation } from "react-router-dom";
export default function Detail() {
  // 接收 state 参数
  const stateCfg = useLocation();
  const {
    state: { id, title, content },
  } = stateCfg;
  return (
    <div>
      <span>{id}</span> -<span>{title}</span> -<span>{content}</span>
    </div>
  );
}

09-编程式路由

09-编程式路由\pages\Home\Message\index.jsx

import React, { Component, useState } from "react";
import { Link, useNavigate, Outlet } from "react-router-dom";

export default function Message() {
  const [message] = useState([
    { id: 1, title: "消息1", content: "内容1" },
    { id: 2, title: "消息2", content: "内容2" },
    { id: 3, title: "消息3", content: "内容3" },
    { id: 4, title: "消息4", content: "内容4" },
  ]);
  const navigate = useNavigate();
  function showDetail(message) {
    // navigate('/about')
    // 但是去子路由的时候就不能带斜杠了
    // 目前 navigate 携带参数只能携带 state 参数,search 和 params 参数不可以携带
    navigate("detail", {
      replace: true,
      state: message,
    });
  }
  return (
    <div>
      <ul>
        {message.map((el) => {
          return (
            <li key={el.id}>
              {/* 路由 search 参数 */}
              <Link
                to="detail"
                state={{
                  ...el,
                }}
              >
                {el.title}
              </Link>
              <button onClick={() => showDetail(el)}>查看详情</button>
            </li>
          );
        })}
      </ul>
      <hr />
      {/* 指定 Detail 的展示位置 */}
      <Outlet />
    </div>
  );
}

09-编程式路由\pages\Home\Message\Detail\index.jsx

import React from "react";
import { useLocation } from "react-router-dom";
export default function Detail() {
  // 接收 state 参数
  const stateCfg = useLocation();
  const {
    state: { id, title, content },
  } = stateCfg;
  return (
    <div>
      <span>{id}</span> -<span>{title}</span> -<span>{content}</span>
    </div>
  );
}

10-uselnRouterContext

10-useInRouterContext\components\Demo.jsx

import React from "react";
import { useInRouterContext } from "react-router-dom";

export default function Demo() {
  console.log("demo --- useInRouterContext", useInRouterContext()); // demo --- useInRouterContext false
  return <div>Demo</div>;
}

10-useInRouterContext\components\Header.jsx

import React from "react";
import { useNavigate, useInRouterContext } from "react-router-dom";

export default function Header() {
  const navigate = useNavigate();
  // 只要是在路由内 useInRouterContext() 就为 true
  console.log("header --- useInRouterContext", useInRouterContext()); // header --- useInRouterContext true
  function back(params) {
    navigate(-1);
  }
  function forward(params) {
    navigate(1);
  }
  return (
    <div>
      <button onClick={back}>后退</button>
      <button onClick={forward}>前进</button>
    </div>
  );
}

11-useNavigationType

import React, { Component } from "react";
import { useNavigationType } from "react-router-dom";

export default function News() {
  // POP 刷新
  // PUSH
  // REPLACE
  // 三种情况,我们这里是用的 PUSH
  console.log("News --- useNavigationType", useNavigationType());

  return (
    <div>
      <ul>
        <li>News 1</li>
        <li>News 2</li>
        <li>News 3</li>
        <li>News 3</li>
      </ul>
    </div>
  );
}

12-useOutlet

import React, { Component, useState } from "react";
import { NavLink, Outlet, useOutlet } from "react-router-dom";

export default function Home() {
  // 如果嵌套路由没有挂载,则result为nu11
  // 如果嵌套路由已经挂载,则展示嵌套的路由对象
  console.log("Home --- useOutlet", useOutlet());
  return (
    <div style={{ padding: "10px" }}>
      <div style={{ border: "1px solid red" }}>
        <h2>导航区</h2>
        <div>
          <a style={{ float: "left", marginRight: "10px" }}>About</a>
          <a style={{ color: "red" }}>Home</a>
        </div>
      </div>
      <div style={{ border: "1px solid green", marginTop: "10px" }}>
        <h2>展示区</h2>
        <h2>Home</h2>
        <NavLink to="message">Message</NavLink>
        <NavLink to="news">News</NavLink>
        {/* 指定路由组件呈现的位置, 类似Vue的 route-view */}
        <Outlet />
      </div>
    </div>
  );
}

13-useResolvedPath

import React, { Component } from "react";
import { useResolvedPath } from "react-router-dom";
export default function News() {
  console.log(
    "useResolvedPath",
    useResolvedPath("/user?id=001&name=tom#qwert")
  );
  // {
  //     "pathname": "/user",
  //     "search": "?id=001&name=tom",
  //     "hash": "#qwert"
  // }
  return (
    <div>
      <ul>
        <li>News 1</li>
        <li>News 2</li>
        <li>News 3</li>
        <li>News 3</li>
      </ul>
    </div>
  );
}