一文带你学懂React前端路由😃

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战css

React路由

SPA

即单页面web(single page web application)应用。整个应用只有一个完整的页面,点击页面中的连接不会刷新页面,只会作页面的局部更新。数据都须要经过ajax获取。html

也就是说,正由于有了路由这个技术的存在,才能实现咱们在同一个页面中进行局部刷新(单页面多组件)。前端

路由的理解

  • 一个路由就是一个映射关系(key: value)node

  • key为路径,value多是function(后端路由) 或 component(前端路由);react

  • 后端路由:注册:router.get(path, function(req, res))。当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。web

  • 前端路由:注册:Route path="/test" component={Test}。用于展现页面内容。当浏览器的path变为/test时,当前路由组件就会变成Test组件。好比对于一个在127.0.0.1:3000的页面,当它为127.0.0.1:3000/home(而不是/home.html)显示的就是home组件。ajax

  • 好比下图这个案例,切换的就是页面,而不是组件。(下面会有此案例同个页面多个组件的写法)后端

    luyou_03.gif

首先要认识一下react的一个的插件库react-router-dom(须要手动下载),该库专门用来实现一个SPA应用,基于react的项目基本都会用到它。浏览器

前端路由

1、路由的基本使用

历史记录 (前端路由基础)

在咱们以前的学习BOM中,是有一个history方法的,在这里咱们经过引入一个historyjs文件直接调用历史记录的一些方法。浏览器的历史记录是一个栈的结构。markdown

<script src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
let history = History.createBrowerHistory();  // 直接使用H5推出的history的API
// let history = History.createBrowerHistory();   hash值 锚点跳转(多了个#)
function push(path) {
    history.push(path);   // 入栈
}
function replace(path) {
    history.replace(path);  // 替代栈顶元素
}
function back() {
    history.goBack();   // 回退
}
function forward() {
    history.goForward();   // 前进
}
history.listen(location)=> {  // 监听路径变化
    console.log(location);
}
复制代码

案例

接下来实现上面那个案例。在原生js中是经过<a>标签跳转到不一样的页面,而在react中,是靠路由连接<Link><link/>实现切换组件的(编写路由连接)。注意:这里的Link是从react-router-dom库里面拿的。在组件分别展现的时候须要注册路由route

基本步骤:(1)确认界面中的导航区、展现区;(2)导航区的a标签改成Link标签;(3)展现区的Route标签进行路径的匹配;(4)在<App>的最外侧包裹一个<BrowserRouter>或者<HashRouter>

// App.jsx
import { Link, BrowserRouter, Route } from 'react-router-dom'  // 引入react-router-dom库
// 编写路由连接
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
// 注册路由
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
复制代码

路由在使用的时候,须要在外层中包裹一层<BrowserRouter><BrowserRouter/>,至关于一个路由器,管理里面的东西。并且只能有一个路由器,不能写2个,不然就至关于两个路由器,两个路由器之间是没有数据沟通的。所以能够在App组件渲染的时候,在其外层放路由器。即

// index.js
ReactDOM.render(
    <BrowserRouter>        <App />    </BrowserRouter>,
    document.getElementById('root')
);
复制代码

这样子就能够实现一个SPA了。此时能够看到页面路径发生了变化,并且<Link>标签渲染到浏览器中实际上是转换为<a>标签的,而to转换为href(转换为浏览器认识的标签)。可是是组件的展现而不是页面之间的跳转(没有.html后缀),打开控制台的network也能够看到此时的浏览器并无发送请求。

luyou2_03.gif

若是想要加上上面那个案例的高亮效果,把Link改为NavLink便可(记得从react-router-dom中引入)。默认点击的时候默认给active样式,可是若是想要给的样式名不是active,那就须要加一个activeClassName="..."(这个的默认值是active)

<NavLink activeClassName="home" className="list-group-item" to="/home">Home</NavLink>
//至关于
<NavLink activeClassName="home" className="list-group-item" to="/home" children="Home"></NavLink>
复制代码

总结:NavLink能够实现路由连接的高亮,经过activeClassName指定样式名,标签体内容是一个特殊的标签属性,经过this.props.children能够获取到标签体内容。

上面这种组件就是路由组件,那么它和普通组件还有什么区别呢?

  • 写法不一样。通常组件:直接写组件标签:<home/>

    路由组件:<Route path="/about" component={Home}></Route>

  • 存放位置不一样。通常组件放在components;路由组件通常放在pages中。

  • 接收到的props不一样。通常组件:给它传递什么就收到什么;路由组件:接收到3个固定属性

对于路由组件,咱们打印出它的props属性,这里在用这个组件的时候并无给它传值,可是它会有自带的propshistorylocationmatch)其中history.location=location。而对于普通组件,若是没有给它传值,它打印出来的props就是空的。

props.png 上面说的是路由的基础使用,接下来讲一说在路由中是怎么进行组件之间的传参的。

2、向前端路由传递参数

  1. 传递params参数

    在路由组件传递参数的时候,在Link中传递参数,要在注册的路由将这些参数让Detail接收,采用下面这种方式。此时在Detail组件中打印this.props的话就能够在this.props.match.params里面看到咱们经过Link传递过去的参数。

    <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
    <Route path="/home/message/detail/:id/:title" component={Detail}></Route>
    复制代码
  2. 传递search参数

    search参数在传递的时候形式以下。并且search不用在注册路由的时候接收参数,直接注册便可,在this.props.location.search中就能够找到传递的参数,不过在这里传递的对象是?key=value&key=value,咱们要手动改为{key: value;}的形式;

    可使用引入内置库import qs from queryString,再用qs.parse(search)来处理从this.props中获得的search对象(注意:用parse以后前面仍是会有一个?,用slice(1)截掉便可

    <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
    复制代码
  3. state参数

    上面说的params参数和search参数在传递参数的时候都会将传递的键值对暴露在地址栏上;state和search同样,不用声明接收,直接注册便可;传递参数方式以下(传对象);

    传递以后在this.props.location.state里面就能够找到所传递的参数;注意:路由中的state跟组件中的state是不同的;state参数只是路由中的一个属性,跟组件里面的state的没有关系

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

    用state传递参数的话刷新也能够保留参数。此时虽然参数没有在地址栏,可是也不会丢失,由于在这里用BrowserRouter来管理路由的,它一直在维护浏览器的historyhistory把传递的东西记下了,所以不会丢失。

3、补充知识点..

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

  • 模糊匹配: 【输入的路径】必须包含【匹配的路径】,且顺序要一致。好比把to后面的连接改为home/a/b时,在找home的路由的时候,会先匹配前面的home,匹配到了就找到了。这就是模糊匹配,且默认就是默认匹配。
  • 严格匹配:能够经过exact={true}exact来开启严格匹配

通常状况下咱们不开启严格匹配,由于有时候开启严格匹配会致使没法继续匹配二级路由

// 编写路由连接 输入的路径
<Link to="/home/a/b">Home</Link>
// 注册路由 匹配的路径
<Route exact={true} path="/home" component={Home}></Route>
复制代码

Switch组件和Redirect组件

提升效率:Switch组件。以下代码,经过/home匹配到Home组件以后就不会继续匹配下去了。不然test组件也会被展现在页面中。注意:要从react-router-dom中引入SwitchRedirectreact-router-dom里面的一个内置组件,会让刚刷新浏览器的时候,默认跳转到指定组件。(通常写在全部路由注册的最下方,当全部路由都没法匹配时,跳转到Redirect指定的路由)

<Switch>
    <Route path="/about" component={About}></Route>
    <Route path="/home" component={Home}></Route>
    <Route path="/home" component={test}></Route>
    <Redirect to="/home"/>
</Switch>
复制代码

嵌套组件

  • 注册子路由的时候要写上父路由的path值
  • 路由的匹配是按照注册路由的顺序进行的

通常状况下咱们不会让同一个路径去对应展现多个组件,若是出现这种状况的话就可使用Switch。一般状况下,path和component是一一对应的关系,Switch能够提升路由匹配效率(单一匹配)。

加油!

相关文章
相关标签/搜索