react-router详解

一、前言

本文介绍React的一个重要部分,就是react-router,它是官方维护的,在开发中极为重要。

二、前端路由的原理

前端路由是如何做到URL和内容进行映射呢?监听URL的改变。

2.1URL的hash

url的hash就是锚点,本质上是改变window.location.href属性,我们可以直接赋值location.hash来改变href,并且页面不会刷新,hash的优势就是兼容性好,但是有一个#,个人认为不是很好看。

<div id="app">
  <a href="#/home">home</a>
  <a href="#/about">about</a>
  <div class="router-view"></div>
</div>

<script>
  // 1.获取router-view
  const routerViewEl = document.querySelector(".router-view");

  // 2.监听hashchange
  window.addEventListener("hashchange", () => {
    switch(location.hash) {
      case "#/home":
        routerViewEl.innerHTML = "home";
        break;
      case "#/about":
        routerViewEl.innerHTML = "about";
        break;
      default:
        routerViewEl.innerHTML = "default";
    }
  })
</script>
复制代码

2.2HTML5的History

history是h5新增的,它共有六种方式可以来改变URL,并且不刷新页面。

  1. replaceState:替换原来的路径;
  2. pushState:使用新的路径;
  3. popState:路径的回退;
  4. go:向前或向后改变路径;
  5. forword:向前改变路径;
  6. back:向后改变路径;

三、react-router

在目前流行的三大框架(react、vue、angular)中,都有属于自己的路由
React Router版本4开始,路由不在集中在一个包中进行管理。

  1. react-router是router的核心部分代码;
  2. react-router-dom是用于浏览器的;
  3. react-router-native是用于原生应用的;

3.1安装react-router

yarn add react-router-dom安装react-router-dom会自动帮助我们安装react-router的依赖;

3.2Router的基本使用

react-router提供了一些组件供我们使用:

BrowserRouter和HashRouter
  • Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件;
  • BrowserRouter使用history模式;
  • HashRouter使用hash模式;
Link和NavLink:
  • 通常路径的跳转是使用Link组件,最终会被渲染成a元素;
  • NavLink是在Link基础之上增加了一些样式属性(后续学习);
  • to属性:Link中最重要的属性,用于设置跳转到的路径;
Route:
  • Route用于路径的匹配;
  • path属性:用于设置匹配到的路径;
  • component属性:设置匹配到路径后,渲染的组件;
  • exact:精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件;
import React, { PureComponent } from 'react';

import { BrowserRouter, Route, Link } from 'react-router-dom';

import Home from './pages/home';
import About from './pages/about';
import Profile from './pages/profile';

export default class App extends PureComponent {
  render() {
    return (
      <BrowserRouter>
        <Link to="/">首页</Link>
        <Link to="/about">关于</Link>
        <Link to="/profile">我的</Link>

        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/profile" component={Profile} />
      </BrowserRouter>
    )
  }
}
复制代码

3.3NavLink的使用

NavLink组件提供了路由激活状态时的一些API

  • activeStyle:活跃时(匹配时)的样式;
  • activeClassName:活跃时添加的class;
  • exact:是否精准匹配;

演示activeStyle,路由激活时,显示红色

<NavLink exact to="/" activeStyle={{color: "red"}}>首页</NavLink>
<NavLink to="/about" activeStyle={{color: "red"}}>关于</NavLink>
<NavLink to="/profile" activeStyle={{color: "red"}}>我的</NavLink>
复制代码

在路径匹配上之后,react默认添加了类“active”

.active {
    color: red
}
复制代码

自定义class名称:

<NavLink exact to="/" activeClassName="link-active">首页</NavLink>
<NavLink to="/about" activeClassName="link-active">关于</NavLink>
<NavLink to="/profile" activeClassName="link-active">我的</NavLink>
复制代码
.link-active {
    color: red
}
复制代码

3.4Switch的使用

react-router中只要是路径被匹配到的Route对应的组件都会被渲染;
但是实际开发中,我们往往希望有一种排他的思想:

  • 只要匹配到了第一个,那么后面的就不应该继续匹配了;
  • 这个时候我们可以使用Switch来将所有的Route进行包裹即可;
<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route path="/profile" component={Profile} />
  <Route path="/:userid" component={User} />
  <Route component={NoMatch} />
</Switch>
复制代码

3.5Redirect的使用

Redirect用于路由的重定向,当这个组件出现时,就会执行跳转到对应的to路径中,比如判断用户是否登录。创建一个user.js文件

import React, { PureComponent } from 'react'
import { Redirect } from 'react-router-dom';

export default class User extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      isLogin: false
    }
  }

  render() {
    return this.state.isLogin ? (
      <div>
        <h2>User</h2>
        <h2>用户名: coderwhy</h2>
      </div>
    ): <Redirect to="/login"/>
  }
}
复制代码

在App.js中定义路由

<switch>
    ...其他路由
    <Route path="/login" component={Login} />
</switch>
复制代码

3.6路由嵌套

假设在子页面中再包括两个子页面,示例代码如下:

import React, { PureComponent } from 'react';
import { Route, Switch, Link } from 'react-router-dom';

function AboutProduct(props) {
  return (
    <ul>
      <li>商品列表1</li>
      <li>商品列表2</li>
      <li>商品列表3</li>
    </ul>
  )
}

function AboutMessage(props) {
  return (
    <ul>
      <li>消息列表1</li>
      <li>消息列表2</li>
      <li>消息列表3</li>
    </ul>
  )
}

export default class About extends PureComponent {
  render() {
    return (
      <div>
        <Link to="/about">商品</Link>
        <Link to="/about/message">消息</Link>

        <Switch>
          <Route exact path="/about" component={AboutProduct} />
          <Route path="/about/message" component={AboutMessage} />
        </Switch>
      </div>
    )
  }
}
复制代码

3.7路由跳转

路由跳转可以采用前面学到的<Link></Link><NavLink></NavLink>,也可以采用js代码跳转,但是这样必须拿到history对象:

  • 如果是通过路由跳转过来所渲染的组件,在props里可以拿到history,location,match对象。
  • 如果是在组件里面的普通按钮,想点击跳转页面,该怎么做呢?

react-router通过高阶组件让我们可以拿到相关的信息。如果我们希望在组件中获取到history对象,必须满足以下两个条件:

  • 组件必须包裹在Router组件之内;
  • 组件使用withRouter高阶组件包裹;

3.8参数传递

传递参数有三种方式

  • 动态路由的方式;
  • search传递参数;
  • to传入对象;

3.8.1动态路由的方式
动态路由的方式就是路由参数不是固定的

  • 比如/detail路径对应Detail组件
  • 如果我们把<route />路径写成/detail/:id,那么/detail:123,/detail:abc都会匹配到该route。

当使用动态路由时,我们可以采用this.props.match.params拿到传递的参数。
search传递参数
我们可以在跳转的路径中写query参数

<NavLink to="/detail2?name=why&age=18">详情2</NavLink>
复制代码

使用search传参数时,可以采用this.props.location.search拿到需要的参数
to传入对象传参

<NavLink to={{
    pathname: "/detail2", 
    query: {name: "kobe", age: 30},
    state: {height: 1.98, address: "洛杉矶"},
    search: "?apikey=123"
  }}>
  详情2
</NavLink>
复制代码

使用search传参数时,可以采用this.props.location拿到需要的参数

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享