【前端学习】React学习笔记-ReactRouter6

8 篇文章 0 订阅

跟着尚硅谷的天禹老师学习React
看视频可以直接点击 b站视频地址

概述

在2021年11月,React官方将ReactRouter6调整为ReactRouter的默认版本
1.React Router以3个不同的包发布到npm上,它们分别为:

  1. react-router:路由的核心库,提供了很多的组件和钩子。
  2. react-router-dom:包含了react-router所有内容,并添加了一些专门用于DOM的组件,例如<BrowserRoute/r>
  3. react-router-native:包括react-router所有内容,并添加了一些专门用于ReactNative的API,例如<NativeRouter/>

2、与React Router 5.x版本,改变了:

  1. 内置组件的变化:移除了<Swtich>,新增了<Routes>
  2. 语法的变化:component = {About},变为了 element = {<About />}等
  3. 新增了多个hook:useParams、useNavigate、useMatch等
  4. 官方明确推荐函数式组件

HashRouter BrowserRouter

和React Router5.x一样

Routes和Route

  1. V6版本移除了先前的<Switch/>,引入了新的替代者<Routes>。
  2. <Routes>和<Route>要配合使用,且必须要用 <Routes>包裹<Route>
  3. <Route/>相当于一个if域据,如果其路径和当前URL匹配,则呈现其对应的组件。
  4. 属性用于指定:匹配时是否区分大小写(默认为false)
  5. 当URL发生变化时,<Routes>都会直接查看其所有子<Route>元素以找到最佳匹配并呈现组件。
  6. <Route>也可以嵌套使用,且可配合useRoutes()配置“路由表”,但需要通过<Outlet>组件来渲染其子路由。

Link

和React Router5.x一样

NavLink高亮

现在className可以使用回调函数来写,回调接收一个对象作为参数,里面会有一个名为isActive的属性来标识当前链接是否处于被选中状态,函数需要返回一个style。

Navigate

  1. 作用:只要<Navigate>组件被渲染,就会修改路径,切换视图。
  2. replace属性用于控制跳转模式(push或replace,默认replace为false)

useRoutes

1、定义一个路由表

const element = useRoutes([
    {
      path: "/about",
      element: <About />,
    },
    {
      path: "/home",
      element: <Home />,
    },
    {
      path: "/",
      element: <Navigate to="/about" />,
    },
  ]);

2、直接插进jsx中

<div className="col-xs-6">
	<div className="panel">
		<div className="panel-body">
			{element}
		</div>
	</div>
</div>

嵌套路由

Outlet

和Vue的路由导入很相似,Vue使用的是<router-view>

目录结构

在这里插入图片描述

代码

App.js

/* App.js */
import React, { Component } from "react";
import { NavLink, useRoutes } from "react-router-dom";
import routesMap from "./routes";
export default function App() {
  function computeClass({ isActive }) {
    return isActive ? "list-group-item highlight" : "list-group-item";
  }
  const element = useRoutes(routesMap);
  return (
    <div>
      <div className="row">
        <div className="col-xs-offset-2 col-xs-8">
          <div className="page-header">
            <h2>React Router Demo</h2>
          </div>
        </div>
      </div>
      <div className="row">
        <div className="col-xs-2 col-xs-offset-2">
          <div className="list-group">
            {/* 在React中靠路由链接实现切换组件 */}
            <NavLink className={computeClass} to="/about">
              About
            </NavLink>
             {/* 如果希望匹配到子路由时当前链接不高亮,可以加上end属性 */}
            <NavLink className={computeClass} end to="/home">
              Home
            </NavLink>
          </div>
        </div>
        <div className="col-xs-6">
          <div className="panel">
            <div className="panel-body">
              {/* 注册路由 */}
              {/* <Routes>
                <Route path="/about" element={<About />} />
                <Route path="/home" element={<Home />} />
                <Route path="/" element={<Navigate to="about" />}></Route>
              </Routes> */}
              {/* 更简单的写法
              优化:可以在外部写一个路由表然后再引入 */}
              {element}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

路由表 routes/index.js

/* routes/index.js */
import Home from "../pages/Home";
import About from "../pages/About";
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: "message", element: <Message /> },
      { path: "news", element: <News /> },
    ],
  },
  {
    path: "/",
    element: <Navigate to="/about" />,
  },
];

Home.jsx

/* Home.jsx */
import React from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Home() {
  return (
    <div>
      <h1>Home</h1>
      <div>
        <ul className="nav nav-tabs">
          <li>
            <NavLink className="list-group-item" to="message">
              News
            </NavLink>
          </li>
          <li>
            <NavLink className="list-group-item" to="news">
              News
            </NavLink>
          </li>
        </ul>
        {/* 指定路由组件呈现的位置 */}
        <Outlet />
      </div>
    </div>
  );
}

路由传参(useParams、useMatch、useSearchParams、useLocation)

和React Router 5.x差不多,有params、match、search、state传参。
对应API:useParams、useMatch、useSearchParams、useLocation(从中可以取state)。
对应传参方式:在路径中显式写上占位符(params和match)、拼接search参数(有点像后端的query)、在Link/NavLink中声明state属性。
App.jsx

import React from "react";
import { NavLink, useRoutes } from "react-router-dom";
import routesMap from "./routes";
export default function App() {
  function computeClass({ isActive }) {
    return isActive ? "list-group-item highlight" : "list-group-item";
  }
  const element = useRoutes(routesMap);
  return (
    <div>
      <div className="row">
        <div className="col-xs-offset-2 col-xs-8">
          <div className="page-header">
            <h2>React Router Demo</h2>
          </div>
        </div>
      </div>
      <div className="row">
        <div className="col-xs-2 col-xs-offset-2">
          <div className="list-group">
            {/* 在React中靠路由链接实现切换组件 */}
            <NavLink className={computeClass} to="/about">
              About
            </NavLink>
            {/* 如果希望匹配到子路由时当前链接不高亮,可以加上end属性 */}
            <NavLink className={computeClass} end to="/home">
              Home
            </NavLink>
          </div>
        </div>
        <div className="col-xs-6">
          <div className="panel">
            <div className="panel-body">
              {/* 注册路由 */}
              {/* <Routes>
                <Route path="/about" element={<About />} />
                <Route path="/home" element={<Home />} />
                <Route path="/" element={<Navigate to="about" />}></Route>
              </Routes> */}
              {/* 更简单的写法
              优化:可以在外部写一个路由表然后再引入 */}
              {element}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

routes/index.js

/* routes/index.js */
import Home from "../pages/Home";
import About from "../pages/About";
import Message from "../pages/Message";
import News from "../pages/News";
import Detail from "../pages/Detail";

import { Navigate } from "react-router-dom";
export default [
  {
    path: "/about",
    element: <About />,
  },
  {
    path: "/home",
    element: <Home />,
    children: [
      {
        path: "message",
        element: <Message />,
        children: [
          {
            // 传递params和match参数时
            // path:'detail/:id/:title/:content',
            path: "detail",
            element: <Detail />,
          },
        ],
      },
      { path: "news", element: <News /> },
    ],
  },
  {
    path: "/",
    element: <Navigate to="/about" />,
  },
];

Message.jsx

/* Message.jsx */
import React, { useState } from "react";
import { Link, Outlet } from "react-router-dom";
export default function Message() {
  const [messages] = useState([
    { id: 1, title: "消息1", content: "内容1" },
    { id: 2, title: "消息2", content: "内容2" },
    { id: 3, title: "消息3", content: "内容3" },
  ]);
  return (
    <div>
      <ul>
        {messages.map((message) => {
          return (
            // 路由链接
            <li key={message.id}>
              <Link
                // 使用params/match传参
                // to={`detail/${message.id}/${message.title}/${message.content}`}
                // 使用search传参
                // to={`detail?id=${message.id}&title=${message.title}&content=${message.content}`}
                // 使用state传参
                to="detail"
                state={{
                  id: message.id,
                  title: message.title,
                  content: message.content,
                }}
              >
                {message.title}
              </Link>
            </li>
          );
        })}
      </ul>
      <hr />
      {/* 指定路由组件展示的位置 */}
      <Outlet />
    </div>
  );
}

Detail.jsx

/* Detail.jsx */
import React from "react";
import {
  useParams,
  useMatch,
  useSearchParams,
  useLocation,
} from "react-router-dom";

export default function Detail() {
  // 使用params传参
  // const params = useParams();
  // 使用match传参
  // const match = useMatch("/home/message/detail/:id/:title/:content");
  // 使用search传参
  // const [search, setSearch] = useSearchParams();
  // 使用location获取state参数
  const location = useLocation();
  const stateParams = location.state;
  console.log(location);
  return (
    <div>
      {/* <button
        onClick={() => {
          setSearch("id=haha&title=haha&content=haha");
        }}
      >
        点我更新search参数
      </button> */}
      <ul>
        {/* 使用params传参 */}
        {/* <li>id:{params.id}</li>
        <li>title::{params.title}</li>
        <li>content:{params.content</li> */}
        {/* 使用match传参 */}
        {/* <li>id:{match.params.id}</li>
        <li>title::{match.params.title}</li>
        <li>content:{match.params.content</li> */}
        {/* 使用search传参 */}
        {/* <li>id:{search.get("id")}</li>
        <li>title:{search.get("title")}</li>
        <li>content:{search.get("content")}</li> */}
        {/* 使用state传参 */}
        <li>id:{stateParams.id}</li>
        <li>title:{stateParams.title}</li>
        <li>content::{stateParams.content}</li>
      </ul>
    </div>
  );
}

编程式路由导航

借助useNavigate钩子实现编程式路由跳转

import { useNavigate } from "react-router-dom";

const navigate = useNavigate();
// 跳转
function showDetail(message) {
    navigate("detail", {
      replace: false, // 本身false就是默认值
      state: {
        id: message.id,
        title: message.id,
        content: message.content,
      }
    });
  }

前进后退

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>
      <h2>React Router Demo</h2>
      <button onClick={back}>后退</button>
      <button onClick={forward}>前进</button>
    </div>
  );
}

useInRouterContext

判断当前路由是否处于路由上下文中,即当前组件是否包含在BrowserRouter或者HashRouter的标签中,一般来讲都是直接在App标签外包一层Router类标签,所以没啥用,除非引入了第三方组件库等情况。

useNavigationType

返回当前的导航类型,即用户是如何来到当前页面的,会返回POP、PUSH、REPLACE中的一个,POP指的是直接在浏览器中直接打开了这个路由组件(或刷新页面)。

useOutlet

用来呈现当前组件中渲染的嵌套路由,如果嵌套路由没有挂载,则result为null,如果嵌套路由已经挂载则展示嵌套的路由对象。

useResolvedPath

给定一个URL值,解析其中的path、search、hash值。

案例

需求

在这里插入图片描述

目录

在这里插入图片描述

代码

index.js,和5的教程没有太大变化

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")
);

routes/index.js,涉及了路由表的配置

import Home from "../pages/Home";
import About from "../pages/About";
import Message from "../pages/Message";
import News from "../pages/News";
import Detail from "../pages/Detail";

import { Navigate } from "react-router-dom";
export default [
  {
    path: "/about",
    element: <About />,
  },
  {
    path: "/home",
    element: <Home />,
    children: [
      {
        path: "message",
        element: <Message />,
        children: [
          {
            // 传递params和match参数时
            // path:'detail/:id/:title/:content',
            path: "detail",
            element: <Detail />,
          },
        ],
      },
      { path: "news", element: <News /> },
    ],
  },
  {
    path: "/",
    element: <Navigate to="/about" />,
  },
];

App.jsx,涉及路由表的使用

import React from "react";
import { NavLink, useRoutes } from "react-router-dom";
import routesMap from "./routes";
import Header from "./components/Header";
export default function App() {
  function computeClass({ isActive }) {
    return isActive ? "list-group-item highlight" : "list-group-item";
  }
  const element = useRoutes(routesMap);
  return (
    <div>
      <div className="row">
        <div className="col-xs-offset-2 col-xs-8">
          <div className="page-header">
            <Header />
          </div>
        </div>
      </div>
      <div className="row">
        <div className="col-xs-2 col-xs-offset-2">
          <div className="list-group">
            {/* 在React中靠路由链接实现切换组件 */}
            <NavLink className={computeClass} to="/about">
              About
            </NavLink>
            {/* 如果希望匹配到子路由时当前链接不高亮,可以加上end属性 */}
            <NavLink className={computeClass} end to="/home">
              Home
            </NavLink>
          </div>
        </div>
        <div className="col-xs-6">
          <div className="panel">
            <div className="panel-body">
              {/* 注册路由 */}
              {/* <Routes>
                <Route path="/about" element={<About />} />
                <Route path="/home" element={<Home />} />
                <Route path="/" element={<Navigate to="about" />}></Route>
              </Routes> */}
              {/* 更简单的写法
              优化:可以在外部写一个路由表然后再引入 */}
              {element}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

Header.jsx,涉及前进后退功能

/* 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>
      <h2>React Router Demo</h2>
      <button onClick={back}>后退</button>
      <button onClick={forward}>前进</button>
    </div>
  );
}

About.jsx,用了一下useState钩子

/* About.jsx */
import React from "react";
export default function About() {
  const [sum, setSum] = React.useState(1)
    return <div>About</div>;
}

Home.jsx,涉及了Outlet的使用

/* Home.jsx */
import React from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Home() {
  return (
    <div>
      <h1>Home</h1>
      <div>
        <ul className="nav nav-tabs">
          <li>
            <NavLink className="list-group-item" to="message">
              News
            </NavLink>
          </li>
          <li>
            <NavLink className="list-group-item" to="news">
              News
            </NavLink>
          </li>
        </ul>
        {/* 指定路由组件呈现的位置 */}
        <Outlet />
      </div>
    </div>
  );
}

Message.jsx,涉及了React Router 5.x的路由传参

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

export default function Message() {
  const navigate = useNavigate();
  const [messages] = useState([
    { id: 1, title: "消息1", content: "内容1" },
    { id: 2, title: "消息2", content: "内容2" },
    { id: 3, title: "消息3", content: "内容3" },
  ]);
  // 跳转
  function showDetail(message) {
    // 只支持replace和state
    // 如果希望使用search、match、params需要手动拼在url中
    navigate("detail", {
      replace: false, // 本身false就是默认值
      state: {
        id: message.id,
        title: message.id,
        content: message.content,
      },
    });
  }
  return (
    <div>
      <ul>
        {messages.map((message) => {
          return (
            // 路由链接
            <li key={message.id}>
              <Link
                // 使用params/match传参
                // to={`detail/${message.id}/${message.title}/${message.content}`}
                // 使用search传参
                // to={`detail?id=${message.id}&title=${message.title}&content=${message.content}`}
                // 使用state传参
                to="detail"
                state={{
                  id: message.id,
                  title: message.title,
                  content: message.content,
                }}
              >
                {message.title}
              </Link>
              <button
                onClick={() => {
                  showDetail(message);
                }}
              >
                查看详情
              </button>
            </li>
          );
        })}
      </ul>
      <hr />
      {/* 指定路由组件展示的位置 */}
      <Outlet />
    </div>
  );
}

Detail.jsx 涉及了接收路由参数

import React from "react";
import {
  useParams,
  useMatch,
  useSearchParams,
  useLocation,
} from "react-router-dom";

export default function Detail() {
  // 使用params传参
  // const params = useParams();
  // 使用match传参
  // const match = useMatch("/home/message/detail/:id/:title/:content");
  // 使用search传参
  // const [search, setSearch] = useSearchParams();
  // 使用location获取state参数
  const location = useLocation();
  const stateParams = location.state;
  console.log(location);
  return (
    <div>
      {/* <button
        onClick={() => {
          setSearch("id=haha&title=haha&content=haha");
        }}
      >
        点我更新search参数
      </button> */}
      <ul>
        {/* 使用params传参 */}
        {/* <li>id:{params.id}</li>
        <li>title::{params.title}</li>
        <li>content:{params.content</li> */}
        {/* 使用match传参 */}
        {/* <li>id:{match.params.id}</li>
        <li>title::{match.params.title}</li>
        <li>content:{match.params.content</li> */}
        {/* 使用search传参 */}
        {/* <li>id:{search.get("id")}</li>
        <li>title:{search.get("title")}</li>
        <li>content:{search.get("content")}</li> */}
        {/* 使用state传参 */}
        <li>id:{stateParams.id}</li>
        <li>title:{stateParams.title}</li>
        <li>content::{stateParams.content}</li>
      </ul>
    </div>
  );
}

总结

  1. BrowserRouter、HashRouter和5版本一样
  2. Routes和Route
    • Routes替代了原来的Swtich,并提供了嵌套路由的功能,useRoutes提供了配置路由表的功能,可以与Outlet使用路由表配置嵌套路由。
  3. Link与NaviLink,Link和5版本一样。NavLink的className提供了回调的写法,可以指定高亮时的样式名,并且可以加一个end路由,使得在子NavLink被选中时只有子组件高亮,而自身不高亮。
  4. Navigate,只要渲染到页面上,就会修改页面路径,替代了原来的Redirect,并可以指定跳转模式是否为replace。
  5. Outlet,和Vue的router-view相似
  6. useRoutes,创建嵌套路由表。
  7. useNavigate,返回一个函数用来实现编程式导航。
  8. useParams,返回当前匹配路由的params参数,类似5版本中的match.params
  9. useSearchParams,接收到的是一个数组,不能直接使用,数组第一个元素要借助其实例的get方法拿到值,第二个元素提供了修改url中search参数的能力。
  10. useLocation,获取当前location信息,替代了5版本中类式组件的location属性。
  11. useMatch,返回当前匹配信息,替代5版本中类式组件的match属性。
  12. useNavigationType、useOutlet、useResolvePath是新的方法。

一个不错的笔记

努力学习的汪 / 洪学习笔记

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值