React18 | React Router6 知识梳理

251 阅读7分钟

React Router,客户端路由,可以将 URL 地址和 React 组件进行映射,当URL地址发生变化时,它会根据设置自动的切换到指定组件。

1 安装

npm install react-router-dom@6 -S

三个包

  1. react-router:核心库,提供了核心组件、钩子。
  2. react-router-dom:所有内容,并添加一些专门用于 DOM 的组件,例如 <BrowserRouter>
  3. react-router-native:所有内容,并添加一些专门用于 ReactNative 的API,例如:<NativeRouter>等。

2 组件

2.1 前置操作 <BrowserRouter> <HashRouter>

和 Redux 的 Provider 类似,要使得路由生效,需要使用<BrowserRouter>包裹整个 App 组件。

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";

ReactDOM.render(
  <BrowserRouter>
    {/* 整体结构(通常为App组件) */}
  </BrowserRouter>,root
);

<HashRouter>作用与<BrowserRouter>一样,但它修改的是地址栏的hash值(#后面的)。

2.2 注册路由 <Routes/> <Route/>

...
import { Link, Route, Routes } from 'react-router-dom';

const Home = ()=>{...};
const About = () => {...};

const App = () => {
  return <div> App
    <ul>
      <li> <Link to='/'> home </Link> </li>
      <li> <Link to='/about'>about</Link> </li>
    </ul>
        
    <Routes>
      <Route path="/" element={<Home/>}/>
      <Route path="/about" element={<About/>}/>
    </Routes>
  </div>;
};

Route 是路由的映射组件,将 url 和 React 组件进行映射。

  • path —— 要匹配的路径
  • element —— 路径匹配后挂载的组件
  • index —— 布尔值,路由是否作为默认组件显示

Routes 是一个存放 Route 的容器。当浏览器的地址发生变化时,会自动对 Routes 中的所有 Route 进行匹配,匹配到的则显示,其余 Route 则不再继续匹配。

杂七杂八的属性

<Route caseSensitive>:匹配时是否区分大小写(默认 false)。

2.3 路由导航 <Link> <NavLink>

Link 组件生成超链接,点击后会修改浏览器地址栏的 url,但并不会真的向服务器发送请求。<Link to="/路径">按钮</Link>

NavLink 是特殊版本的 Link,可以根据不同的情况设置不同的样式。它可以设置如下属性:

  • activeClassName —— 字符串,当链接被激活时为该链接添加指定的 CSS 类名
  • activeStyle —— style 对象,当链接被激活时为该链接应用指定的样式
  • isActive —— 函数,自定义判断链接是否激活的逻辑
  • style —— 函数,动态设置链接的样式
  • className —— 函数,动态设置链接的 class 值
<NavLink to="/home" activeClassName="active-link">Home</NavLink>
<NavLink to="/home" activeStyle={{ color: 'red' }}>Home</NavLink>

//isActive回调的默认参数是 match 和 location 
<NavLink to="/home" 
  isActive={(match, location) => { match && location.pathname === '/home';}
>Home</NavLink>//className回调的默认参数为{isActive:true/false},表示该NavLink是否被激活
//我们直接用{isActive}解构拿到它
<NavLink to="login"
  className = { 
    ({ isActive }) => { return isActive ? 'xxx' : 'aaa'}
  }
>login</NavLink>
  
<NavLink to="/home" 
  style={(match, location) => {color: match ? 'red' : 'blue'}
>Home</NavLink>


/*
	默认情况下,当子组件匹配成功,父组件的导航也会高亮,
	添加了end属性后,父组件不会再有高亮
*/
<NavLink to="home" end >home</NavLink>

2.4 重定向 <Navigate/>

将请求重定向到一个新的位置,经常用来进行权限的处理。例如:登录时则正常显示组件,未来登录时则跳转到登录页面。

{isLogin && <SomeAuthComponent/>}
{!isLogin && <Navigate to={"/login" replace={true}}></Redirect>}

上例中,如果 isLogin 的值为 true,表示用户已经登录,若用户登录,则挂载对应组件。

若isLogin值为false,则挂载 Navigate 组件触发重定向,重定向会使得路径跳转到登录页面。

  • to —— 重定向的目标地址,可以是一个字符串也可以是一个对象
  • from —— 需要重定向的地址
  • push/replace —— 布尔值,是否使用 push/replace 方式对请求进行重定向,push 默认 true,replace 默认 false

3 路由表 Hook useRoutes()

step1 创建路由表

import About from '../pages/About'
import Home from '../pages/Home'
......
import {Navigate} from 'react-router-dom'

export default [
  {
    path:'/',
    element:<Navigate to="/about"/>
  },
  {
    path:'/about',
    element:<About/>
  },
  {
    path:'/home',
    element:<Home/>,
    children:[  //嵌套路由
      {
        path:'news',//不要写/news
        element:<News/>
      },
      {
        path:'message',
        element:<Message/>,
      }
    ]
  }
]

Step2 注册路由

根据路由表生成对应的路由规则,即自动创建了<Routes><Route>

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>
			......
      {element}
      {/* line12相当于生成下面这堆↓
      <Routes>
        <Route path="/home" element={<Home/>}/>
        <Route path="/about" element={<About/>}/>
        ...
    	</Routes> */}
		  ......
		</div>
	)
}

Step3 渲染路由组件

路由导航触发 url 更新以及渲染路由匹配到的组件。

	//点击则渲染news和message两个子路由组件
	<Link to="news">News</NavLink>
	<Link to="message">Message</NavLink>
	{/* 子路由组件呈现的位置 */}
	<Outlet />
import React from 'react'
import {useNavigate} from 'react-router-dom'

export default function Demo() {
  const navigate = useNavigate()
  const handle = () => {
    //法1:指定具体的路径和配置对象
    //配置对象里只能配state参数,如果要用params和search,请直接拼在path里
    navigate('/login', {
      replace: false,
      state: {a:1, b:2}
    }) 
    //法2:传入数值进行前进或后退
    navigate(-1)
  }
  
  return (
    <div><button onClick={handle}>按钮</button></div>
  )
}

4 其他 Hook

4.1 useNavigate()

返回一个函数用来实现编程式路由导航

一言以蔽之,取代掉 Link 和 NavLink,用来实现自动跳转等功能。

import React from 'react'
import {useNavigate} from 'react-router-dom'

export default function Demo() {
  const navigate = useNavigate()
  const handle = () => {
    //法1:指定具体的路径和配置对象
    //配置对象里只能配state参数,如果要用params和search,请直接拼在path里
    navigate('/login', {
      replace: false,
      state: {a:1, b:2}
    }) 
    //法2:传入数值进行前进或后退
    navigate(-1)
  }
  
  return (
    <div><button onClick={handle}>按钮</button></div>
  )
}

4.2 useParams()

返回当前匹配路由的params参数

① 在路由表中占位

export default [
  {
    path:'/about/:id/:title',
    element:<About/>
  },

② 触发路由更新时携带 params

...
<Link className="..." 
  to={`about/${m.id}/${m.title}`}>...
</Link>

③ 在组件中获取传过来的 params

let { id,title } = useParams();

4.3. useSearchParams()

search 参数和 params 参数不同,不需要占位。

返回一个包含两个值的数组,内容分别为:当前的seaech参数、更新search的函数。

import React from 'react'
import {useSearchParams} from 'react-router-dom'

export default function Detail() {
	const [search,setSearch] = useSearchParams()
	const id = search.get('id')
	const title = search.get('title')
	return (
    <button onClick={()=>
      setSearch('id=008&title=哈哈')}>
	  ......
	)
}

【补】search 参数、params 参数和 state 参数

  1. search 参数:通过 URL 查询字符串传递数据。/path?param1=value1&param2=value2
  • history.push({ search: '?param1=value1' }) -- 编程路由导航
  • <Link to={{ search: '?param1=value1' }}>Link</Link>
  1. params 参数:通过路由路径的占位符来传递数据。/path/:param1/:param2
  • history.push('/path/value1/value2')
  • <Link to="/path/value1/value2">Link</Link>
  1. state 参数:通过路由的 state 属性传递数据。一个对象,可以包含任意类型的数据。
  • history.push({ pathname: '/path', state: { data: 'value' } })
  • <Link to={{ pathname: '/path', state: { data: 'value' } }}>Link</Link>

4.4. useLocation()

获取当前页面的位置信息——location 对象。

可以通过location 对象来获取 serach 和 state 参数。

import React from 'react'
import {useLocation} from 'react-router-dom'

export default function Detail() {
	const x = useLocation()
	console.log(x)
  /*location对象: 
		{
      hash: "",   当前页面URL的hash部分
      key: "ah9nv6sz",
      pathname: "/login",
      search: "?name=zs&age=18",
      state: {a: 1, b: 2}
    }*/
  //从location钩子返回的对象中解构出state参数
  const {state:{id,title}} = useLocation()
	return (
  ...
  	<li>{id}<li/>
    <li>{title}<li/>
  ...
	)
}

state 参数的传递

<Link className="..." 
  to="about"
  state={{id:m.id,title:m.title}}
</Link>

4.5 useMatch()

检查当前页面的 URL 是否与指定的路径匹配。

line5:当前页面 url 是否和/login/:x/:y匹配,如不匹配,返回 null,如匹配,返回 match 对象。

match 对象用于获取与当前 URL 相关的信息

<Route path="/login/:page/:pageSize" element={<Login />}/>
<NavLink to="/login/1/10">登录</NavLink>

export default function Login() {
  const match = useMatch('/login/:x/:y')
  console.log(match) //输出match对象
  /* match对象
  	{
      params: {x: '1', y: '10'}     URL中的动态路径参数相对应的键值对对象。
      pathname: "/LoGin/1/10"       当前页面的url
      pathnameBase: "/LoGin/"	      省略了动态路径参数
      pattern: {                    与当前 URL 进行匹配的路由模式
      	path: '/login/:x/:y', 
      	caseSensitive: false,       大小写是否敏感
      	end: false                  路径是否必须以斜杠结束
      }
    }
  */
  return (
		...
  )
}

【补】location 和 match 对象

两者都提供了有关 URL 的信息,但用途略有不同:

  • match 对象用于确定 URL 是否与特定的路由模式匹配,并获取匹配成功后的动态路径参数等信息。帮助我们在组件中根据 URL 的匹配情况来执行不同的操作。
  • location 对象主要用于获取当前页面的位置信息。帮助我们在组件中获取当前页面的 URL、路径、查询字符串等信息,并根据需要执行导航操作或其他页面相关的操作。

5 不常用 Hook

5.1 useInRouterContext()

如果组件在 <Router> 的上下文中呈现,则 useInRouterContext 钩子返回 true,否则返回 false。

用 BrowserRouter 包裹整个 App 组件,则 App 及其所有子组件就处于 Router 的上下文中。

5.2 useNavigationType()

返回当前的导航类型(用户是如何来到当前页面的)。

返回值:POPPUSHREPLACE

备注:POP是指在浏览器中已经打开了这个路由组件,然后刷新了页面。

5.3 useOutlet()

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

const result = useOutlet()
console.log(result)
// 如果嵌套路由没有挂载,则result为null
// 如果嵌套路由已经挂载,则展示嵌套的路由对象

5.4 useResolvedPath()

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

6 React router5 和 6 的区别

  1. 内置组件的变化:移除<Switch/>,新增 <Routes/>等。

  2. 语法的变化:component={About} 变为 element={<About/>}等。

  3. 新增多个hook:useParamsuseNavigateuseMatch等。

  4. 官方明确推荐函数式组件。

参考

[1] react-router – 李立超 | lilichao.com

[2] www.bilibili.com/video/BV1wy…