React---路由

124 阅读9分钟

React Router

1、概述

1、React Router 会以三个不同的包发布到npm上,它们分别是:

  • react-router:路由的核心库,提供了很多的:组件、钩子。

  • react-router-dom:包含react-router所有内容,并添加一些专门用于DOM的组件,例如<BrowserRouter>

  • react-router-native:包括react-router所有内容,并添加一些专门用于ReactNative的API,例如<NativeRouter>

React Router 5

Component

1.<BrowserRouter>

  1. 作用:<BrowserRouter>用于包裹整个应用

  2. 示例代码:

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

ReactDOM.render(

  <BrowserRouter>
    <App />
  </BrowserRouter>
  
  , document.getElementById("root")
);

在这里插入图片描述

2.<HashRouter>

  1. 作用:与<BrowserRouter>一样,但是修改的是地址栏的hash值

  2. 示例代码:

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


ReactDOM.render(

  <HashRouter>
    <App />
  </HashRouter>
  
  , document.getElementById("root")
);

在这里插入图片描述

3.<Link>

  1. 作用:修改URL地址,并且不会发送网络请求

  2. 注意:它需要在外侧用<BrowserRouter><HashRouter>包裹,否则会报错

  3. 示例代码:

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

export default function App() {
  return (
    <div>
    
      <Link to="/home">Home</Link>
      
      <br />
      <br />
      
      <Link to="/about">About</Link>
      
    </div>
  );
}

在这里插入图片描述

4.NavLink

  1. 作用:与<Link>类似,且可以实现导航高亮的效果(即给了一个"active"的样式名)

  2. 示例代码:

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

export default function App() {
  return (
    <div>
    
    //注意:NavLink默认类名是active
      <NavLink to="/home">Home</NavLink>
      
      <br />
      <br />
      
      <NavLink to="/about">About</NavLink>
      
    </div>
  );
}

在这里插入图片描述

5. <Route>

  1. 作用:根据路径来匹配相对应的组件,随后渲染到页面上

  2. 示例代码:

import React from "react";
import { Route, Link } from "react-router-dom";
//导入创建的两个组件
import Home from "./components/Home";
import About from "./components/About";

export default function App() {
  return (
    <div>
      <Link to="/home">Home</Link>
      <br />
      <br />
      <Link to="/about">About</Link>
      <br />
      <br />
      
      <Route path="/home" component={Home} />
      <Route path="/about" component={About} />
      
    </div>
  );
}

在这里插入图片描述

6.<switch>

  1. 作用:可以提高路由的匹配效率(单一匹配)

  2. 示例代码:

  • 不使用<switch>

当不使用<switch>的话,如果后续的地址有多个重复的,那么将会全部匹配并且渲染到页面上

import React from "react";
import { Route, Link } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";

export default function App() {
  return (
    <div>
      <Link to="/home">Home</Link>
      <br />
      <br />
      <Link to="/about">About</Link>
      <br />
      <br />
      <Route path="/home" component={Home} />
      
      <Route path="/about" component={About} />
      <Route path="/about" component={Test} />
      
    </div>
  );
}

在这里插入图片描述

  • 使用<switch>

使用<switch>之后无论后续的地址重复多少个,它都只会匹配第一个相同的地址,然后渲染当前的组件到页面上

import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";

export default function App() {
  return (
    <div>
      <Link to="/home">Home</Link>
      <br />
      <br />
      <Link to="/about">About</Link>
      <br />
      <br />
      
      <Switch>
        <Route path="/home" component={Home} />
        
        <Route path="/about" component={About} />
        <Route path="/about" component={Test} />
        
      </Switch>
      
    </div>
  );
}

在这里插入图片描述

7.<Redirect>

  1. 作用:当所有的路由都没有匹配到时,跳转到Redirect指定的路由

  2. 示例代码;

import React from "react";
import { Route, Link, Switch, Redirect } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";

export default function App() {
  return (
    <div>
      <Link to="/home">Home</Link>
      <br />
      <br />
      <Link to="/about">About</Link>
      <br />
      <br />
      <Switch>
        <Route path="/home" component={Home} />
        <Route path="/about" component={About} />
        
        //当浏览器中的路径与上述不匹配时,将会被重定向到/home路径上
        <Redirect to="/home" />
        
      </Switch>
    </div>
  );
}

在这里插入图片描述

向路由组件传递参数

  1. params参数传递
{/* params参数传递---路由连接(携带参数) */}
<Link to="/home/tom/18">Home</Link>

{/* params参数传递---注册路由(声明接收) */}
<Route path="/home/:name/:age" component={Home} />

// 接收参数---props.match.params
const { name, age } = props.match.params;

示例代码:

App.jsx代码:

import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Home from "./components/Home";

export default function App() {
  return (
    <div>
    
      {/* params参数传递---路由连接(携带参数) */}
      <Link to="/home/tom/18">Home</Link>
      
      <Switch>
      
        {/* params参数传递---注册路由(声明接收) */}
        <Route path="/home/:name/:age" component={Home} />
        
      </Switch>
    </div>
  );
}


Home.jsx代码:

import React from "react";

export default function Home(props) {

  // 接收参数---props.match.params
  const { name, age } = props.match.params;
  
  return (
    <>
      <div>Home</div>
      <div>
      
        接收到的参数为:{name},{age}
        
      </div>
    </>
  );
}

在这里插入图片描述

  1. search参数传递
{/* search参数传递---路由连接(携带参数) */}
<Link to="/about?name=tom&age=18">About</Link>

{/* params参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/about" component={About} />

// 接收参数--- props.location.search;
const data = props.location.search;

示例代码:

App.jsx代码:

import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import About from "./components/About";

export default function App() {
  return (
    <div>
    
      {/* search参数传递---路由连接(携带参数) */}
      <Link to="/about?name=tom&age=18">About</Link>
      
      <Switch>
      
        {/* params参数传递---注册路由(无需声明接收,正常注册即可) */}
        <Route path="/about" component={About} />
        
      </Switch>
    </div>
  );
}

About.jsx代码:

import React from "react";

export default function About(props) {
  // 接收参数--- props.location.search;
  const data = props.location.search;
  return (
    <>
      <div>About</div>
      
      {/* 获取到的search是urlencoded编码字符串,需要进行处理 */}
      <div>接收到的参数为:{data}</div>
      
    </>
  );
}

在这里插入图片描述

  1. state参数传递
{/* state参数传递---路由连接(携带参数) */}
<Link to={{ pathname: "/test", state: { name: "tom", age: 18 } }}>Test</Link>

{/* state参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/test" component={Test} />

// 接收参数--- props.location.state;
const { name, age } = props.location.state;

示例代码:

App.js代码:

import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Test from "./components/Test";

export default function App() {
  return (
    <div>
    
      {/* state参数传递---路由连接(携带参数) */}
      <Link to={{ pathname: "/test", state: { name: "tom", age: 18 } }}>Test</Link>
      
      <Switch>
      
        {/* state参数传递---注册路由(无需声明接收,正常注册即可) */}
        <Route path="/test" component={Test} />
        
      </Switch>
    </div>
  );
}


Test.js代码

import React from "react";

export default function Test(props) {

  // 接收参数--- props.location.state;
  const { name, age } = props.location.state;
  
  return (
    <>
      <div>Test</div>
      <div>
        接收到的参数为:{name},{age}
      </div>
    </>
  );
}

在这里插入图片描述

  1. 整体代码
App.js代码


import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";

export default function App() {
  return (
    <div>
    
      {/* params参数传递---路由连接(携带参数) */}
      <Link to="/home/tom/18">Home</Link>
      
      <br />
      <br />
      
      {/* search参数传递---路由连接(携带参数) */}
      <Link to="/about?name=tom&age=18">About</Link>
      
      <br />
      <br />
      
      {/* state参数传递---路由连接(携带参数) */}
      <Link to={{ pathname: "/test", state: { name: "tom", age: 18 } }}>Test</Link>
      
      <br />
      <br />
      <Switch>
      
        {/* params参数传递---注册路由(声明接收) */}
        <Route path="/home/:name/:age" component={Home} />
        
        {/* params参数传递---注册路由(无需声明接收,正常注册即可) */}
        <Route path="/about" component={About} />
        
        {/* state参数传递---注册路由(无需声明接收,正常注册即可) */}
        <Route path="/test" component={Test} />
        
      </Switch>
    </div>
  );
}

Home.js代码

import React from "react";

export default function Home(props) {

  // 接收参数---props.match.params
  const { name, age } = props.match.params;
  
  return (
    <>
      <div>Home</div>
      <div>
        接收到的参数为:{name},{age}
      </div>
    </>
  );
}



About.js代码

import React from "react";

export default function About(props) {

  // 接收参数--- props.location.search;
  const data = props.location.search;
  
  return (
    <>
      <div>About</div>
      {/* 获取到的search是urlencoded编码字符串,需要进行处理 */}
      <div>接收到的参数为:{data}</div>
    </>
  );
}



Test.js代码

import React from "react";

export default function Test(props) {

  // 接收参数--- props.location.state;
  const { name, age } = props.location.state;
  
  return (
    <>
      <div>Test</div>
      <div>
        接收到的参数为:{name},{age}
      </div>
    </>
  );
}

在这里插入图片描述

React Router 6

React Router 6与React Router 5.x 版本相比,改变了什么?

  • 内置组件的变化移除<Switch/>,新增<Routes/>

  • 语法的变化:component={About}变为element={<About/>}

  • 新增多个hook:useParamsuseNavigateuseMatch

component

1. <Routes/>

1、作用:

  • v6版本移除了<Switch>,引入新的替代者<Routes>

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

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

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

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

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

2、示例代码:

 <Routes>
 
     {/* path属性用于定义路径,element属性用于定义当前路径所对应的组件 */}
     <Route path="/home" element={<Home />} />
     
 </Routes>

2.<Navigate>

1、作用:只要<Navigate>组件被渲染,就会修改当前的路径,跳转到指定的路径

2、replace属性用来控制跳转模式(push或replace,默认是push)

3、示例代码:

import React from "react";
import { Route, Link, Routes, Navigate } from "react-router-dom";
import Home from "./components/Home";

export default function App() {
  return (
    <div>
      <Link to="/home">Home</Link>
      <Routes>
        <Route path="/home" element={<Home />} />
        
        {/* 当路径为"/"时,就会渲染Navigate组件,随后跳转到"/home"路径去 */}
        <Route path="/" element={<Navigate to="/home" />} />
        
      </Routes>
    </div>
  );
}

3.<NavLink>

1、作用:与v5的作用一样,但可以通过传递一个函数来自定义样式

2、示例代码:

import React from "react";
import { Route, Link, Routes, Navigate, NavLink } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";

export default function App() {
  return (
    <div>
      <NavLink
        to="/home"
        className={({ isActive }) => {
          console.log("home", isActive);
          return isActive ? "base" : "";
        }}
      >
        Home
      </NavLink>
      <br />
      <br />
      <Link to="/about">About</Link>
      <Routes>
        <Route path="/home" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </div>
  );
}

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

在这里插入图片描述在这里插入图片描述

4. <Outlet>

  1. 当产生了嵌套的时候,渲染器对应的后续子路由

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

  3. 实例代码:

路由表配置代码(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" />
  }
]



Home.js代码:

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

export default function Home() {
  return (
    <div>
      <h2>Home组件内容</h2>
      <div>
        <ul>
          <li>
            {/* 子路由中的to的三种写法:
                1. to='/home/news'
                2. to='./news'
                3. to='news'
            */}
            <NavLink to="news">News</NavLink>
          </li>
          <li>
            <NavLink to="message">Message</NavLink>
          </li>
        </ul>
        
        {/* 指定路由组件呈现的位置
            
            会将路由表中home下的子路由渲染到此处
        */}
        <Outlet />
        
      </div>
    </div>
  );
}

image.png

Hooks

1.useRoutes()

1、作用:根据路由表,来动态创建<Routes><Route>

2、示例代码:

路由表配置代码(src/routes/index.js):

import Home from "../components/Home";
import About from "../components/About";
import { Navigate } from 'react-router-dom'

export default [
  {
    path: '/home',
    element: <Home />
  },
  {
    path: '/about',
    element: <About />
  },
  {
    path: '/',
    element: <Navigate to="/home" />
  }
]


App.js代码:

import React from "react";
import {
  Link,
  useRoutes
} from "react-router-dom";
import routes from "./routes";

export default function App() {

//根据路由表生成对应的路由规则
  const element = useRoutes(routes);
  
  return (
    <div>
      <Link to="/home">Home</Link>
      <br />
      <br />
      <Link to="/about">About</Link>
      
      //生成路由
      {element}
      
    </div>
  );
}

在这里插入图片描述

2. useNavigate()

  1. 作用:返回一个函数用来实现编程式导航

  2. 示例代码:

Message.jsx代码:


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

export default function Message() {

  const navigate = useNavigate();

  const showDetail = (m) => {
    //第一种使用方法:指定具体的路径
    // 第一个参数是to(要去的路径),第二个参数是传递的参数
    navigate("detail", {
      replace: false,
      state: {
        id: m.id,
        title: m.title,
        content: m.content,
      },
    });
  };
  
      
  //第二种使用方法:传入数值进行前进或后退,类似于5.x中的history.go()方法
  const go = () => {
    navigate(1);
  };

  const forward = () => {
    navigate(-1);
  };
  
  return (
    <div>
      <button onClick={() => showDetail(m)}>查看详情</button>
      <button onClick={forward}>前进</button>
      <button onClick={go}>后退</button>
    </div>
  );
}

3.useParams()

  1. 作用:获取当前匹配的路由所传递的params参数,类似于5.x中的match.params

  2. 示例代码:

Message.jsx代码:

//与5.x写法相同,在路径上携带参数
<Link to={`detail/${m.id}/${m.title}/${m.content}`}>
    {m.title}
</Link>


路由表代码:

{
    path: 'detail/:id/:title/:content',
    element: <Detail />
}


Detail.jsx代码:

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

export default function Detail() {

  //使用useParams()来获取传递过来的参数
  const { id, title, content } = useParams();

  return (
    <ul>
      <li>{id}</li>
      <li>{title}</li>
      <li>{content}</li>
    </ul>
  );
}

useParams传递的参数:

image.png

image.png

4. useMatch()

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

  2. 示例代码:

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


const match = useMatch("/home/message/detail/:id/:title/:content");
console.log(match);

image.png

5. useSearchParams()

  1. 作用:用于读取和修改当前位置的URL上的查询字符串

  2. 返回一个包含两个值的数组,内容分别是:当前的search参数,更新search的函数

3.示例代码:

Message.jsx代码:

<Link
to={`detail?id=${m.id}&title=${m.title}&content=${m.content}`}
>
    {m.title}
</Link>


路由表代码无需更改!


Detail.jsx代码:

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

export default function Detail() {

  // search:接收到的参数,setSearch可以更新接收到的参数
  const [search, setSearch] = useSearchParams();

  // 通过调用search上的get方法,来指定获取数据
  const id = search.get("id");
  const title = search.get("title");
  const content = search.get("content");
  
  return (
    <ul>
      <li>{id}</li>
      <li>{title}</li>
      <li>{content}</li>
    </ul>
  );
}

search的值:

image.png

image.png

6. useLocation()

  1. 作用:获取当前location信息,对标5.想中的路由组件的location属性

  2. 示例代码:

Message.jsx代码:

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


路由表代码无需更改!


Detail.jsx代码:
import React from "react";
import { useLocation } from "react-router-dom";

export default function Detail() {

  // 连续解构赋值
  const {
    state: { id, title, content },
  } = useLocation();

  return (
    <ul>
      <li>{id}</li>
      <li>{title}</li>
      <li>{content}</li>
    </ul>
  );
}


image.png

image.png

7. useInRouterContext()

  1. 作用:如果组件在的上下文中呈现,则useInRouterContext钩子返回true,否则返回false

  2. 示例代码:

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

console.log(useInRouterContext());

image.png

8. useNavigationType()

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

  2. 返回值:POP、PUSH、REPLACE

  3. 备注:POP是指在浏览器中直接打开了这个路由组件(刷新页面)

  4. 示例代码:

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


console.log(useNavigationType());

image.png

9. useOutlet()

  1. 作用:用来呈现当前组件中渲染的嵌套组件

  2. 示例代码:

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


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

image.png

10. useResolvedPath()

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

  2. 示例代码:

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


console.log(useResolvedPath("/user?id=001&name=tom#qwe"));

image.png