18. React路由

文章目录

  • 1.React路由相关概念
    • 1.1 SPA应用
    • 1.2 路由Route的理解
      • 1.2.1 什么是路由
      • 1.2.2 路由Route的分类
        • 后端路由
        • 前端路由
    • 1.3 react-router-dom
      • 1.3.1 react-router-dom是什么
      • 1.3.2 react-router-dom相关API
        • 内置组件
        • 其他
  • 2.React路由的基本使用
    • 2.1 安装react-router-dom
    • 2.2 路由的配置
    • 2.3 路由组件和一般组件
      • 路由组件
      • 一般组件
    • 2.4 路由组件和一般组件的最大区别
      • 路由组件
        • history
        • location
        • match
      • 一般组件
    • 2.5 路由组件和一般组件的区别总结
      • 写法不同
      • 存放位置不同
      • 接收的props不同
    • 2.6 封装 NavLink (代码优化)
    • 2.7 children属性对 2.6的再次优化
      • 使用children="xxx"可以给标签体赋值,也就可以把标签体内容以属性的形式赋值
  • 3. 多级路径
    • 3.1 多级路径样式丢失
    • 3.2 解决方法
      • 3.2.1 使用从项目根路径引入(常用、通用)
      • 3.2.2 使用文件的绝对路径(只适用于react)
      • 3.2.3 使用HashRouter替换BrowserRouter(很少用)
  • 4.路由的模糊匹配和严格匹配
    • 4.1 精准匹配 exact={true} 或者 exact
    • 4.2 模糊匹配
    • 4.3 严格匹配不要随便开启
  • 5. Redirect 重定向
  • 6. 路由传参(声明、接收、获取)
    • 6.1 params参数传递(浏览器请求路径暴露参数)
      • 浏览器请求格式
      • 6.1.1 Link中配置请求参数的value
      • 6.1.2 Route中配置接收参数的key
      • 6.1.3 接收params参数
    • 6.2 search参数(浏览器地址栏会暴露参数 )
      • 浏览器请求格式
      • 6.2.1 Link配置请求参数
      • 6.2.2 Route配置接收参数(无需配置接收,但是浏览器地址栏会暴露参数)
      • 6.2.3 接收search参数
      • 6.2.4urlencoded编码
        • react脚手架自带一个组件 querystring
        • stringify(obj对象) 把对象转为key=value&key2=value2
        • parse(urlencoded) 把urlencoded编码字符串转为对象
    • 6.3 state参数
      • 浏览器请求格式
      • 此处的参数state和组件的属性state没有任何关系
      • 6.3.1 Link配置传递的参数和路径
      • 6.3.2 Route配置接收参数(无需配置接受,而且浏览器地址栏不会暴露参数)
      • 6.3.3 接收state参数
      • 6.3.4 state参数在页面F5刷新的时候会不会丢失
  • 7. push和replace设置路由跳转方式
    • push和replace
    • 7.1 push 在Link中默认为true
    • 7.2 replace在Link中设置
  • 8. 编程式路由
    • 8.1 编程式路由跳转
    • 8.2 this.props.history.goBack() 回退 相当于浏览器回退
    • 8.3 this.props.history.goForword() 前进 相当于浏览器前进
    • 8.4 this.props.history.go(n) 根据n的值 决定前进还是后退
  • 9. withRouter的使用
    • 9.1 withRouter的作用
    • 9.2 示例
  • 10. BrowserRouter和HashRouter的区别
    • 10.1 底层原理不一样:
    • 10.2 浏览器地址的path路径不一样
    • 10.3 刷新操作对路由中this.props.history.state参数的影响
    • 10.4 HashRouter可以解决路径错误的相关问题问题

1.React路由相关概念

1.1 SPA应用

  1. 单页Web应用(simgle page web application , 简称 SPA)
  2. 整个应用只有一个完整的页面
  3. 点击页面中的链接不会刷新页面,只做页面局部更新
  4. 数据都需要通过ajax请求获取,并在前端异步展现

1.2 路由Route的理解

1.2.1 什么是路由

  1. 一个路由就是一个 key:value 映射关系
  2. 在路由中,key指的是路径,value可以是一个方法function或者组件component

1.2.2 路由Route的分类

后端路由

  1. 后端路由的value是function,用来处理客户端提交的请求
  2. 注册路由:router.get(path,function(req,res))
  3. 工作流程:当node收到一个请求,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据

前端路由

  1. 浏览器端路由,value是组件component,用于展示页面内容
  2. 注册路由:
  3. 工作流程:当浏览器path为 /login ,当前的路由组件就会变成 Login组件

1.3 react-router-dom

1.3.1 react-router-dom是什么

  1. react的一个插件库
  2. 专门用来实现一个SPA应用
  3. 基于react的项目基本都会用到这个库

1.3.2 react-router-dom相关API

内置组件

BrowserRouter是路由路径不带 #
HashRouter是路由路径带 #
  • path=“/login”
  • component={组件名}

  1. 如果不要有高亮效果,可以使用

  2. 如果导航条需要高亮效果,使用
    并且配置一个属性值
    <NavLink activeClassName="样式属性" className="list-group-item">下载模块</NavLink>
    
  • 假如有50个注册路由
<Route path="/demo01" component={Demo01}>
<Route path="/demo02" component={Demo02}>
<Route path="/demo03" component={Demo03}>
....
<Route path="/demo50" component={Demo50}>
  • 在不使用Switch的时候,注册路由假如有50个
  • 请求 http://localhost:3000/demo01
  • 在运行的时候如果点击Demo01对应的NavLink,那么路由匹配到 /demo01,加载组件 Demo01,
  • 然后继续匹配后面的路由组件,
  • 这样导致的后果是效率低
  • 所以要使用 Switch 这个内置组件,把所有注册的路由组件包括起来
  • 代码如下
<Switch>
	<Route path="/demo01" component={Demo01}>
	<Route path="/demo02" component={Demo02}>
	<Route path="/demo03" component={Demo03}>
	....
	<Route path="/demo50" component={Demo50}>
	<Route path="/demo01" component={Demo0101}>
</Switch>

其他

  1. history对象
  2. match对象
  3. withRouter函数

2.React路由的基本使用

2.1 安装react-router-dom

yarn add react-router-dom

2.2 路由的配置

<div classname="list-group">
	//在 路由器 BrowserRouter 中配置 路由链接 Link
	<BrowserRouter>
		<Link className="list-group-item" to="/test01"></Link>
		<Link className="list-group-item" to="/test02"></Link>
	</BrowserRouter>
</div>
...
<div className="panel">
	<div className="panel-body">
		<Route path="test01" component={组件名}/>
		<Route path="test02" component={组件名}/>
	</div>
</div>

浏览器地址栏的对应地址路径如下:
http://localhost:3000/test01
http://localhost:3000/test02

注意
整个项目必须使用一个路由器,所以在src/index.js中使用路由器把App组件包裹住

ReactDOM.render(
    <BrowserRouter>
    	<App />
    </BrowserRouter>,
  document.getElementById('root')
);

2.3 路由组件和一般组件

路由组件

  1. 使用
  2. 把所有路由组件单独放在一个文件夹内 src/path

一般组件

  1. 程序员手动引入组件
  2. 所有的一般组件单独放在一个文件夹内 src/component

2.4 路由组件和一般组件的最大区别

路由组件

路由组件可以接收到路由器自动传入的prop参数,这是路由组件和一般组件的最大区别
18. React路由_第1张图片

history

location

match

一般组件

一般组件接收的props,是手动传入的,传什么参数,props接收到的是什么参数

2.5 路由组件和一般组件的区别总结

写法不同

  • 一般组件
<Demo />
  • 路由组件
<Route path="/demo" component={Demo}

存放位置不同

  • 一般组件 scr/components
  • 路由组件 src/pages

接收的props不同

  • 一般组件:组件标签传递什么接收的props就是什么
  • 路由组件:路由器默认传入三个重要固定属性
    • history
    • location
    • match

18. React路由_第2张图片

  • 编码时会用的属性如下
    18. React路由_第3张图片

2.6 封装 NavLink (代码优化)

  • 使用MyNavLink
import logo from './logo.svg';

import './App.css';
import MyNavLink from './components/MyNavLink/MyNavLink';

function App() {
  return (
    <div className="App">
      <div className="list-group">
        <MyNavLink to="/home" title="主页"}/>
        <MyNavLink to="/download" title="下载管理"/>
        <MyNavLink to="/user" title="用户管理"/>
      </div>
    </div>
  );
}

export default App;
  • 手动封装的 MyNavLink
import React, {Component} from "react"
import {NavLink} from "react-router-dom"


export default class MyNavLink extends Component{
    
    render(){
        const {to,title} = this.props
        return (
            <NavLink activeClassName="lchh" className="list-group-item" to={to}>{title}</NavLink>
        )
    }
}

2.7 children属性对 2.6的再次优化

使用children="xxx"可以给标签体赋值,也就可以把标签体内容以属性的形式赋值

<Demo>demo</Demo>
<Demo children="demo"/>
//这两种写法是等价的
  • App
import logo from './logo.svg';

import './App.css';
import MyNavLink from './components/MyNavLink/MyNavLink';

function App() {
  return (
    <div className="App">
      <div className="list-group">
        <MyNavLink to="/home" children="主页"></MyNavLink>
        <MyNavLink to="/download" children="下载管理"></MyNavLink>
        <MyNavLink to="/user" children="用户管理"></MyNavLink>
      </div>
    </div>
  );
}

export default App;

  • MyNavLink
import React, {Component} from "react"
import {NavLink} from "react-router-dom"


export default class MyNavLink extends Component{
    
    render(){
        return (
            <NavLink activeClassName="lchh" className="list-group-item" {...this.props}/>
        )
    }
}
  • 自闭和标签的标签体内容可以通过 children属性去配置
  • 如果需要接收的属性太多可以通过展开运算符去快速配置 {…this.props.xxx}

3. 多级路径

3.1 多级路径样式丢失

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210419141608179.png)
  • 多级路径的路由
<NavLink to="/hx/download" activeClassName="test" className="list-group-item">下载模块</NavLink>
<NavLink to="/hx/update" activeClassName="test" className="list-group-item">上传模块</NavLink>
<NavLink to="/hx/change" activeClassName="test" className="list-group-item">修改模块</NavLink>
<NavLink to="/hx/add" activeClassName="test" className="list-group-item">添加模块</NavLink>
<Route path="/hx/about" component={Dwonload}/>
<Route path="/hx/home" component={Update}/>
<Route path="/hx/about" component={Change}/>
<Route path="/hx/home" component={Add}/>
  • public/index.html文件中我们引入样式css文件
//在 public/index.html文件中我们引入样式css文件
<link rel="stylesheet" href="./css/bootstrap.css">
  • 在初始化加载的时候,react脚手架是单页面程序,所以在index.html会引入bootstrap.css,路径为
http://localhost:3000/bootstrap.css
  • 切换路由 /hx/download,此时我发现样式会丢失,因为请求css样式的路径已经变了
http://localhost:3000/hx/bootstrap.css

这样的路径是错误的,匹配不到

  • 但是我们查看NetWork发现仍然返回200,查看Response发现返回的是index.html
  • 在react脚手架中,如果请求的路径资源匹配不到,那么会默认返回index.html

3.2 解决方法

3.2.1 使用从项目根路径引入(常用、通用)

  • 在 react脚手架中,public 文件夹相当于整个项目的根路径,下面的去掉“.”,是使用默认从项目根路径引入,所以不会样式丢失
<link rel="stylesheet" href="/css/bootstrap.css">

3.2.2 使用文件的绝对路径(只适用于react)

  • %PUBLIC_URL% 就是项目的根路径的绝对路径
  • 这种写法只适用于react%PUBLIC_URL%
<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">

3.2.3 使用HashRouter替换BrowserRouter(很少用)

  • 在src/index.js中替换掉之前的BrowserRouter
  • 点击请求这个连接 http://localhost:3000/#/hx/download
  • 因为HashRouter的请求路径中有 #
  • 所以 # 后面的的路径被认为是前端页面的资源定位,就不会向 http://localhost:3000服务器再次请求 bootstrap.css样式文件,使用的是初始化页面加载的时候的样式
http://localhost:3000/hx/bootstrap.css

4.路由的模糊匹配和严格匹配

4.1 精准匹配 exact={true} 或者 exact

<Route exact={true} path="/demo" to={Demo}/>

或者

<Route exact path="/demo" to={Demo}/>

4.2 模糊匹配

  • 默认的时候是模糊匹配
  • Link的路径必须包含注册路由的路径,且和注册路由相同的部分必须顺序保持一致

4.3 严格匹配不要随便开启

  • 开启严格匹配模式,可能会导致无法匹配二级路由

5. Redirect 重定向

  • 页面初始化加载的时候,指定加载一个默认组件
  • 配置在注册路由的后面,表示所有路由都匹配不到,就会加载Redirect指定的组件
  • 多用于初始化默认加载
    <Switch>
    	<Route path="/about" component={About}/>
    	<Route path="/home" component={Home}/>
    	<Redirect to="/about"/>
    </Switch>
    
    • 页面初始化,默认加载About组件

6. 路由传参(声明、接收、获取)

6.1 params参数传递(浏览器请求路径暴露参数)

浏览器请求格式

http://localhost:3000/home/message/001/消息001

6.1.1 Link中配置请求参数的value

<Link to={`/home/message/${obj.id}/${obj.title}`}>Message01</Link>

6.1.2 Route中配置接收参数的key

<Route path="/home/message/:id/:title" component={Message}>

6.1.3 接收params参数

const {id,title} = this.props.match.params

18. React路由_第4张图片

6.2 search参数(浏览器地址栏会暴露参数 )

浏览器请求格式

http://localhost:3000/home/message/?id=001&title=消息001

6.2.1 Link配置请求参数

<Link to={`/home/message/?id=${obj.id}&title=${obj.title}`}>Message01</Link>

6.2.2 Route配置接收参数(无需配置接收,但是浏览器地址栏会暴露参数)

<Route path="/home/message" component={Message}/>

6.2.3 接收search参数

18. React路由_第5张图片

import qs from "querystring"
.....
console.log(this.props.location.search)
//输出结果如下    ?id=001&title=消息01

//去掉字符串第一位的 ?,并转为对象
const obj = qs.parse(this.props.location.search.slice(1))

6.2.4urlencoded编码

search: “?id=001&title=消息1” 这种就是urlencoded编码

react脚手架自带一个组件 querystring

stringify(obj对象) 把对象转为key=value&key2=value2

parse(urlencoded) 把urlencoded编码字符串转为对象

import qs from "querystring"
let obj = {id:"001", title:"消息01"}
console.log(qs.stringify(obj)) 
//输出结果     id=001&title=消息01



let strCar = "carName=bmw&price=199"
console.log(qs.parse(strCar))
//输出结果      {carName:"bmw",price:"199"}

6.3 state参数

浏览器请求格式

http://localhost:3000/home/message

此处的参数state和组件的属性state没有任何关系

6.3.1 Link配置传递的参数和路径

<Link to={{pathname:"/home/message",state:{id: obj.id,title: obj.title}}}>Message01</Link>

6.3.2 Route配置接收参数(无需配置接受,而且浏览器地址栏不会暴露参数)

6.3.3 接收state参数

18. React路由_第6张图片

const {id,title} = this.props.location.state

6.3.4 state参数在页面F5刷新的时候会不会丢失

  • BrowserRouter一直在维护 浏览器历史记录,正常情况下刷新页面,state参数不会丢失
  • 但是一旦清除浏览器历史记录或者缓存,那么再刷新的时候state参数会丢失成为undefined
  • 所以在使用state参数的时候,在给组件赋值的时候最好带上||{},意思是如果获取的值为undefined那么赋值为{}
const {id,title} = this.props.location.state || {}

7. push和replace设置路由跳转方式

push和replace

  • push 会留下历史记录,默认为true
  • replace 不会留下历史记录,而是替换掉上一次历史记录

7.1 push 在Link中默认为true

7.2 replace在Link中设置

<Link replace={true} to={{pathname:"/home/message",state:{id: obj.id,title: obj.title}}}>Message01</Link>
  • 浏览器历史记录是栈的模式 先进后出

18. React路由_第7张图片

8. 编程式路由

18. React路由_第8张图片

8.1 编程式路由跳转

  • this.props.history.push(path, state) //正常跳转

  • this.props.history.replace(path,state) // 替换跳转

  • state 参数是针对使用state传参的方式使用传入参数

8.2 this.props.history.goBack() 回退 相当于浏览器回退

8.3 this.props.history.goForword() 前进 相当于浏览器前进

8.4 this.props.history.go(n) 根据n的值 决定前进还是后退

  • n=1 前进1步
  • n=2 前进2步
  • n=-1 后退1步
  • n=-2 后退两步

9. withRouter的使用

9.1 withRouter的作用

  • 一般组件不能够使用路由组件的特有属性 this.props

  • withRouter(param)是一个函数,

  • 传入参数param是一个普通组件

  • 返回值是一个新的组件,携带有路由组件特定的参数

  • withRouter作用:

    • 使普通组件也能够操作路由组件的特有参数
  • 参考: 6路由传参(声明、接收、获取)

9.2 示例

import React, { Component } from 'react'
import {withRouter} from "react-router-dom"

class Test extends Component {
    render() {
        return (
            <div>
                
            </div>
        )
    }
}
export default withRouter(Test)

10. BrowserRouter和HashRouter的区别

10.1 底层原理不一样:

  • BrowserRouter使用的是经过react封装后的(H5的history的API),不兼容IE9以下版本
  • HashRouter使用的是URL的哈希值,不能使用H5的history的API

10.2 浏览器地址的path路径不一样

  • BrowserRouter的路径中没有# ,如 localhost:3000/home/a/b/c
  • HashRouter的路径中有# ,如 localhost:3000/#/home/a/b/c

10.3 刷新操作对路由中this.props.history.state参数的影响

  • BrowserRouter没有任何影响,因为state保存在history对象中
  • HashRouter刷新后会导致路由参数state丢失

10.4 HashRouter可以解决路径错误的相关问题问题

  • 参考: 3.1 多级路径样式丢失

你可能感兴趣的:(React,react)