react路由学习笔记

517 阅读5分钟

前端路由原理

路由是通过bom的history实现的,可以通过以下的方式实现

<a href="http://www.baidu.com" onclick="return push('/test1')"></a>

<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
let history = History.createBrowserHistory()
function push(path){
    history.push()
}

路由的基本使用

更准确的说是react-router-dom的基本使用(区别于react-router)

react-router-dom简介

1、react的插件库

2、专门用来实现一个SPA项目

3、基本所有的项目都要用到此库

安装

npm install react-router-dom

引入

// 引入Link和Router
import { Link, Route } from 'react-router-dom'
// 引入路由组件
import About from './components/About'
import Home from './components/Home'

使用

  <Link className="list-group-item" to="/about">about</Link>
  <Link className="list-group-item" to="/home">home</Link>
 <Route path="/about" component={About}/>
 <Route path="/home" component={Home}/>

注意,,要包在BrowserRouter下,还需要在Link和Router外面包同一个BrowserRouter。

但是这样的写法比较麻烦,一般采用在App外面包一个全局的BrowserRouter的方式。 如下:

   import { BrowserRouter } from 'react-router-dom'
   <BrowserRouter>
      <App />
    </BrowserRouter>,

路由组件一般写在pages文件夹下。

路由组件和一般组件

1、写法不同:

一般组件

路由组件

2、存放位置不同:

一般组件:components文件夹下

路由组件:pages文件夹下

3、接收到的props不同:

一般组件:组件写了什么,就收到什么

路由组件:接收到三个固定的属性

  1. history:
    1. go: ƒ go(n)
    2. goBack: ƒ goBack()
    3. goForward: ƒ goForward()
    4. push: ƒ push(path, state)
    5. replace: ƒ replace(path, state)
  2. location:
    1. hash: ""
    2. pathname: "/about"
    3. search: ""
  3. match:
    1. params: {}
    2. path: "/about"
    3. url: "/about"

NavLink的使用

 <NavLink activeClassName="aaa" className="list-group-item" to="/home">home</NavLink>

可以通过activeClassName设置当前选中状态下的链接的高亮显示样式

NavLink封装

import React, {Component} from 'react'
import { NavLink } from 'react-router-dom'
export default class MyNavLink extends Component {
  render() {
    console.log(this.props)
    // const {to, title} = this.props
    return(
      <NavLink activeClassName="aaa" className="list-group-item" {...this.props}/>
    )
  }
}
  <MyNavlink to='/about'>about</MyNavlink>
  <MyNavlink to='/home'>home</MyNavlink>

这里需要注意的是上面home把home写在中间作为标签体的写法,值会存储到this.props.home中去。myNavlink封装的函数中,标签体可以通过this.props.children拿到。 {...this.props}这种结构赋值的写法可以一次将所有的属性全部加上,包括chidren属性。

Switch组件

如果不用switch包裹,Route会一直匹配下去,如下方代码,如果写了两个/home匹配的路由,那么下面的Home组件和Test组件都会被渲染。

<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Test}/>

你可能会说我们实际开发不可能写两个一样名称的路由,渲染不一样的组件。即使不会像上面的例子这样写,匹配成功之后还要接着往下匹配也会影响性能。绝大部分情况下,我们都是想匹配成功第一个,就结束后面的匹配。

Switch组件可以帮助我们实现这种惰性匹配,只要匹配成功一个就不再接着往下匹配。

<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={test}/>
</Switch>

解决样式丢失问题

根路径问题

我们的react脚手架项目实际上是通过webpack中的devServer服务起的,其根路径实际上对应的我们项目中的public,例如http://localhost:3000/abouthttp://localhost:3000的根路径实际上就对应脚手架项目中的public。

请求资源不存在的情况

如果我们请求的资源并不存在,那么会去找public文件夹下的index.html来兜底。

样式为什么会丢失

在用二级路由我们是这样写的:

<Navlink to='baidu/about'>about</Navlink>
<Navlink to='baidu/home'>home</Navlink><Switch>
<Route path="baidu/about" component={About}/>
<Route path="baidu/home" component={Home}/>
</Switch>

我们的应用bootStrap是这样引的:

 <link rel="stylesheet" href="./bootStrap/bootstrap.css">

正确的资源请求路径应该是下面的路径:

http://localhost:3000/bootStrap/bootstrap.css

但是我们刷新页面,请求路径变成了:

http://localhost:3000/baidu/bootStrap/bootstrap.css

这个路径下botStrap资源并不存在,所以就用public下的index.html兜底,所以就造成了样式的丢失。

解决办法:

1、去掉引用的‘.’,"/bootStrap/bootstrap.css"。因为./表示的是当前路径,去掉'.'则表示的绝对路径,直接去localhost:3000下去找。

2、用‘%PUBLIC_URL%/bootStrap/bootstrap.css’

3、换成hash路由,因为hash路由#后面的参数都不会被作为请求参数传过去,请求只会发#号前面的部分。

路由的精准匹配和模糊匹配

模糊匹配

默认的路由进行模糊匹配,在Navlink中加多层路由,可以匹配上相应的组件。如下面的例子‘/about/a’是可以匹配上About组件的,反之,Route中路由为/about/a,Navlink中路由为/about则匹配不上。

<Navlink to='/about/a'>about</Navlink>
<Route path="/about" component={About}/>

精准匹配

可以通过在Route中添加exact="true"属性(也可以直接写exact),设置精准匹配,路由只有完全对应上才可以匹配成功。ps:严格匹配慎用,可能会导致无法匹配二级路由。

<Route path="/about" exact="true" component={About}/>

Redirect

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

<Switch>
    <Route path="/about" component={About}/>
    <Route path="/home" component={Home}/>
    <Redirect to="/about"></Redirect>
</Switch>

嵌套路由

1、注册子路由时要注意写上父路由的path值

2、路由的匹配顺序是按照路由注册顺序进行的

<ul className="nav nav-tabs">
  <li>
    <Link to="/home/news">News</Link>
  </li>
  <li>
    <Link to="/home/message">Message</Link>
  </li>
</ul>
<Switch>
  <Route path="/home/news" component={News} />
  <Route path="/home/message" component={Message} />
</Switch>

向路由组件传递params参数

params

1、路由链接(携带参数):

<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>

2、注册路由(声明接收)

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

3、接收参数

this.props.match.params

search

1、路由链接

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

2、路由注册

无需声明,直接注册即可

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

3、接收参数

在this.props.location.search中获取。

state

1、路由链接:

<Link to={{pathname:'/home/message/detail/',state:{id:123,title:‘zhangsan’}}}>{msgObj.title}</Link>

2、路由注册

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

3、接收参数

在this.props.location.state中获取。

开启Replace模式

在link上添加replace属性即可。

 <Link replace to={{pathname:'/home/message/detail/',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>

编程式路由

以按钮出发路由跳转为例:

<button onClick={()=>{this.handlePush(msgObj.id,msgObj.title)}}>push</button>
// params形式传递参数
// this.props.history.push(`/home/message/detail/${id}/${title}`)
// search形式传递参数
// this.props.history.push({pathName: `/home/message/detail/?id=${id}&title=${title}`})
// state形式传递参数
this.props.history.push({pathName:'/home/message/detail/',state:{id,title}})

参数的接收同上方通过Link形式传递。

withRouter

withRouter的作用是使得非路由组件也能在props上有history属性,用于编程式路由

1、在非路由组件中引入

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

2、以withRouter包裹的形式暴露出去

export default withRouter(Header)

BrowserRouter和HashRouter的区别

1、底层原理不一样:

BrowserRouter使用的是H5的history API,不兼容IE9及其以下版本,HashRouter使用的是URL的哈希值。

2、path的表现形式不一样

BrowserRouter的路径中没有#,HashRouter的路径中包含#。

3、刷新后对路由state参数的影响

(1)BrowerRouter没有任何的影响,因为state保存在history对象中,只要浏览器还打开,刷新并不会导致参数丢失。

(2)HashRouter刷新后会导致state参数的丢失。

4、HashRouter可以用于解决一些路径错误相关的问题。