07_React 路由

React 路由(5.x版本)

  • 一、相关理解
    • 1、SPA 的理解
    • 2、路由的理解
      • 2.1 什么是路由?
      • 2.2 路由分类
        • 2.2.1 后端路由
        • 2.2.2 前端路由
    • 3、react-router-dom(Web 开发使用) 的理解
  • 二、react-router-dom 相关 API
    • 1、内置组件
      • 1.1 BrowserRouter
      • 1.2 HashRouter
      • 1.3 Route
      • 1.4 Redirect
      • 1.5 Link
      • 1.6 NavLink
      • 1.7 Switch
    • 2、路由的基本使用
    • 3、路由组件和一般组件
      • 3.1 路由组件
      • 3.2 一般组件
    • 4、解决多级路由下页面刷新样式丢失问题
    • 5、路由的模糊匹配与精确匹配
      • 5.1 匹配的路径需要的和顺序都对上,默认就是模糊匹配
      • 5.2 精确匹配 使用 exact 属性
      • 5.3 如果模糊匹配引发异常,才开启 精确匹配,一般不会全部开启精确(严格)匹配
      • 5.4 总结
    • 6、Redirect 的使用
    • 7、二级路由(嵌套路由)
    • 8、向路由组件传递参数
      • 8.1 params 参数
      • 8.2 search 参数
      • 8.3 state 参数(路由组件独有的 state)
    • 9、push 和 replace
    • 10、编程式路由导航
    • 11、withRouter 的使用
    • 12、BrowserRouter 与 HashRouter 的区别

一、相关理解

1、SPA 的理解

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

单页面,多组件

2、路由的理解

2.1 什么是路由?

1、一个路由就是一个映射关系(key:value)
2、key 为路径,value 可能是 function 或 component

2.2 路由分类

2.2.1 后端路由

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

2.2.2 前端路由

1、浏览器端路由:value 是 component, 用于展示页面内容
2、注册路由:
3、工作过程:当浏览器的 path 变成 /test 时,当前路由组件就会变成 Test 组件
4、工作原理:底层原理依靠的是浏览器的 history(BOM 对象上面),专门用来管理路由的,原本底层的操作 API 过于繁琐,所以一般都使用三方封装好的。
history 模式,直接使用 H5 推出的 API,个别旧版本的浏览器可能不支持
hash 值(锚点)跳转不会刷新页面,也会留下历史记录。兼容性好

3、react-router-dom(Web 开发使用) 的理解

1、React 的一个插件库
2、专门用来实现一个 SPA 应用
3、基于 React 的项目基本都会用到此库
4、react-router 有三种:Web(适用 web 开发)、native(适用 React Native 开发)、any(适用任何场景)
5、路由器(router)是用来管理 路由(route) 的

二、react-router-dom 相关 API

npm i react-router-dom@5

1、内置组件

1.1 BrowserRouter

下面代码中相当于有两个 路由器包裹,所以没法统一管理

About Home

1.2 HashRouter

路径都会有一个 # 号,后面的东西都不会作为资源发送给服务器端

1.3 Route

注册路由

1.4 Redirect

放在路由注册的最下方,如果所有的路由都没有匹配上,就跟着 redirect 走

1.5 Link

原生 html 中,使用 a 标签跳转不同的页面
在 React 中靠路由链接实现切换组件—编写路由链接
Link 的属性跟 a 标签一致
外层需要 包裹 或者
没法高亮菜单

1.6 NavLink

点击谁就会默认给谁追加一个 类样式名 .active
有一个 属性名 activeClassName=‘activeClass’

总结:
1、NavLink 可以实现路由链接的高亮,通过 activeClassName 指定样式名
2、组件标签,标签体内容是一个特殊的标签属性
3、通过 this.props.children 可以获取标签体内容

基本使用:

import React, { Component } from 'react'

import { NavLink, Route } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Header from './components/Header'

import './App.css'
// 创建并暴露 App 组件
export default class App extends Component {
  render() {
    return (
      
About Home
) } }

二次封装使用:
MyNavLink 组件

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

export default class MyNavLink extends Component {
  render() {
    let { to, pathName } = this.props
    return (
      
        {pathName}
      
    )
  }
}

App 组件

import React, { Component } from 'react'

import { Route } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Header from './components/Header'
import MyNavLink from './components/MyNavLink'

import './App.css'
// 创建并暴露 App 组件
export default class App extends Component {
  render() {
    return (
      
{/* About Home */}
) } }

MyNavLink 组件的第二种封装(更加简洁好用)

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

export default class MyNavLink extends Component {
  render() {
    return (
      
    )
  }
}

App 组件

import React, { Component } from 'react'
import { Route } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import Header from './components/Header'
import MyNavLink from './components/MyNavLink'
import './App.css'
// 创建并暴露 App 组件
export default class App extends Component {
  render() {
    return (
      
About Home {/* About Home */}
) } }

1.7 Switch

注册的路由一个以上可以包裹起来,这时候匹配到第一个就直接停止了
总结:
1、通常情况下,path 和 component 是一一对应的关系
2、Switch 可以提高路由匹配效率(单一匹配)

import React, { Component } from 'react'

import { Route, Switch } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Test from './pages/Test'
import Header from './components/Header'
import MyNavLink from './components/MyNavLink'

import './App.css'
// 创建并暴露 App 组件
export default class App extends Component {
  render() {
    return (
      
About Home Test {/* About Home */}
) } }

2、路由的基本使用

1、明确好界面中的 导航区、展示区
2、导航区的 a 标签改为 Link 标签

Demo 3、展示区写 Route 标签进行路径的匹配 4、的最外层包裹了一个 或者

3、路由组件和一般组件

总结区别:
1、写法不同:
一般组件:
路由组件: 2、存放位置不同:
一般组件:components
路由组件:pages
3、接收到的 props 不同:
一般组件:与组件标签时传递了什么,就接收什么
路由组件:接收到三个固定的属性

{
    "history": {
        "action": "POP",
        "location": {
            "pathname": "/about",
            "search": "",
            "hash": "",
            "key": "mlt4yu"
        }
    },
    "location": {
        "pathname": "/about",
        "search": "",
        "hash": "",
        "key": "mlt4yu"
    },
    "match": {
        "path": "/about",
        "url": "/about",
        "isExact": true,
        "params": {}
    }
}

3.1 路由组件

规范些的写法是 放到 pages 中
不用传参数也可以收到 props


3.2 一般组件

规范些的写法是 放到 components 中
没有传参就不会收到 props


4、解决多级路由下页面刷新样式丢失问题

BrowserRouter 刷新页面样式丢失,是出现在二级(多级)路由下,引入样式时会将路由路径添加进去,这时候样式就会丢失,react 就会返回 index.html 的内容回来

./ 以当前文件出发,在当前文件夹下面去找
解决方法 1:(去掉 .)
表示直接去 localhost:3000/css/bootstrap.css 查找

解决方法 2:(%PUBLIC_URL%)
绝对路径解决

解决方法 3:将路由模式改为 HashRouter

注意:包管理 npm 和 yarn 不要混着用,否则容易造成包的丢失

5、路由的模糊匹配与精确匹配

5.1 匹配的路径需要的和顺序都对上,默认就是模糊匹配

/home/a/b 和/home 就是可以匹配的

import React, { Component } from 'react'

import { Route, Switch } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Test from './pages/Test'
import Header from './components/Header'
import MyNavLink from './components/MyNavLink'

import './App.css'
// 创建并暴露 App 组件
export default class App extends Component {
  render() {
    return (
      
About Home Test {/* About Home */}
) } }

5.2 精确匹配 使用 exact 属性

import React, { Component } from 'react'

import { Route, Switch } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Test from './pages/Test'
import Header from './components/Header'
import MyNavLink from './components/MyNavLink'

import './App.css'
// 创建并暴露 App 组件
export default class App extends Component {
  render() {
    return (
      
About Home Test {/* About Home */}
) } }

5.3 如果模糊匹配引发异常,才开启 精确匹配,一般不会全部开启精确(严格)匹配

5.4 总结

1、默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序一致)
2、开启严格匹配

3、严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由

6、Redirect 的使用

一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到 Redirect 指定的路由

import React, { Component } from 'react'

import { Route, Switch, Redirect } from 'react-router-dom'

import Home from './pages/Home'
import About from './pages/About'
import Test from './pages/Test'
import Header from './components/Header'
import MyNavLink from './components/MyNavLink'

import './App.css'
// 创建并暴露 App 组件
export default class App extends Component {
  render() {
    return (
      
About Home Test {/* About Home */}
) } }

7、二级路由(嵌套路由)

React 中路由注册从 App 里面开始的,路由的匹配都是优先注册的先匹配
总结:
1、注册子路由时要写上父路由的 path 值
2、路由的匹配时按照注册路由顺序进行匹配

import React, { Component } from 'react'

import { Route, Switch, Redirect } from 'react-router-dom'

import MyNavLink from '../../components/MyNavLink'
import News from './News'
import Message from './Message'

export default class Home extends Component {
  render() {
    return (
      

我是 Home 的页面内容

news Message
) } }

8、向路由组件传递参数

8.1 params 参数

路由链接(携带参数):

{el.title}

注册路由(声明接收):


接收参数

let { id } = this.props.match.params

8.2 search 参数

不需要声明接收, 正常注册路由即可

路由链接(携带参数):

{el.title}

注册路由(无需声明,正常注册即可):


接收参数

this.props.location.search

备注:获取到的 search 时 urlencoded 编码字符串,需要借助 querystring 解析

8.3 state 参数(路由组件独有的 state)

BrowserRouter 一直维护 history,所以刷新页面 state 中的数据不会丢失。如果清空浏览器缓存和历史记录等才会没有 state。

路由链接(携带参数):


  {el.title}

注册路由(无需声明,正常注册即可):


接收参数

this.props.location.state

备注:参数不体现在地址栏上面,但刷新也可以保留住参数

9、push 和 replace

默认时 push 模式,不做替换,能够留下所有的痕迹

开启 replace 模式:不留下痕迹

10、编程式路由导航

两种模式(push 和 replace)可以携带三种形式的参数,携带参数和路由注册以及接收参数都需要保持一致

借助 this.props.history 对象上的 API 进行前进、后退

this.props.history.replace
this.props.history.push

this.props.history.push(path, state) // state 参数传递

this.props.history.goForward() //前进
this.props.history.goBack() // 后退
this.props.history.go() // 整数为前进 n 步,负数为后退 n 步,0为当前页刷新

11、withRouter 的使用

一般组件没有 history,也就是一般组件中不能用路由导航的 API
withRouter 能够接收一个一般组件,将一般组件加工后,能够拥有路由组件的 API

12、BrowserRouter 与 HashRouter 的区别

1、底层原理不一样
BrowserRouter 使用的是 H5 的 history API,不兼容 IE9 及以下版本
HashRouter 使用的 URL 的哈希值
2、path 表现形式不一样
BrowserRouter 的路径中没有 # ,例如: localhost:3000/demo/test
HashRouter 的路径中有 # ,例如: localhost:3000/#/demo/test
3、刷新后对路由 state 参数的影响
BrowserRouter 没有任何影响,因为 state 保存在 history 对象中
HashRouter 刷新后会导致路由 state 参数的丢失,因为它没有 history 对象
4、备注:HashRouter 可以用于解决一些路径错误相关的问题

你可能感兴趣的:(React,全家桶,react.js,前端,前端框架)