系列文章目录
第一章:React基础知识(React基本使用、JSX语法、React模块化与组件化)(一)
第二章:React基础知识(组件实例三大核心属性state、props、refs)(二)
第三章:React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)
第四章:React脚手架应用(创建脚手架、代理配置、ajax相关、组件通信)(四)
第五章:react-router5路由相关一(路由相关概念、基本使用、NavLink与NavLink的封装、Switch的使用、严格匹配、路由重定向、路由组件与一般组件的区别)(五)
第六章:react-router5路由相关二(嵌套路由、路由传参、replace、编程式路由导航、withRouter的使用、BrowserRouter与HashRouter的区别)(六)
第七章:React-Router6路由相关一(路由的基本使用、重定向、NavLink·、路由表、嵌套路由)(七)
第八章:React-Router6路由相关二(路由传参、编程式路由导航、路由相关hooks)(八)
第九章:React相关扩展一(setState、lazyLoad、Hooks相关)(九)
第十章:React相关扩展二(Fragment、Content、组件优化、render props、错误边界)(十)
第十一章:Redux相关知识(什么是redux、redux的工作原理、redux的核心概念、redux的基本使用)(十一)
第十二章:React-Redux相关知识(什么是react-redux、react-redux的原理、react-redux相关API、react-redux的基本使用)(十二)
文章目录
一、路由相关概念
1.1 SPA的理解
1.单页Web应用(single page web application,SPA)。
2.整个应用只有一个完整的页面。
3.点击页面中的链接不会刷新页面,只会做页面的局部更新。
4.数据都需要通过ajax请求获取, 并在前端异步展现。
1.2 路由的理解
1.什么是路由?
1.一个路由就是一个映射关系(key:value)
2.key为路径, value可能是function或component
2.路由分类
- 后端路由:
1)理解: value是function, 用来处理客户端提交的请求。
2)注册路由: router.get(path, function(req, res))
3)工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由,调用路由中的函数来处理请求, 返回响应数据
- 前端路由:
1)浏览器端路由,value是component,用于展示页面内容。
2)注册路由:
3)工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
3. react-router-dom的理解
1.react的一个插件库。
2.专门用来实现一个SPA应用。
3.基于react的项目基本都会用到此库。
二、路由常用组件的基本使用
2.1 安装
$ npm install react-router-dom@5 --save
安装react-router-dom的产品依赖,会帮助我们将路由操作dom的依赖安装完成
注意: 在跳转路由时,如果路径是/开头的则是绝对路由,否则为相对路由,即相对于“当前URL”进行改变。
-
Redirect组件
可以进行路由的重定向
2.2 基本使用步骤
1.明确好界面中的导航区、展示区
2.导航区写Link标签<Link to="/xxxxx">Demo</Link>
3.展示区写Route标签进行路径的匹配<Route path='/xxxx' component={Demo}/>
4.的最外侧包裹了一个<BrowserRouter>
或<HashRouter>
-
BrowserRouter、HashRouter组件
路由的根组件。
-
Link组件
其中Link标签对A标签进行了封装,可以进行路由的跳转;Link组件只能在Router内部使用,因此使用到Link组件的组件一定要放在顶层的Router之内。
-
Route组件
Route组件则是用来匹配路由对应的页面组件
代码片段(为节省空间,样式代码,一律不写):
App.js
import React, { Component } from 'react'
import {Link,Route} from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 原生html中,靠<a>跳转不同的页面 */}
{/* <a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a> */}
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
Home.jsx
import React, { Component } from 'react'
export default class Home extends Component {
render() {
return (
<h3>我是Home的内容</h3>
)
}
}
About.jsx
import React, { Component } from 'react'
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
)
}
}
index.js
//引入react核心库
import React from 'react'
//引入ReactDOM
import ReactDOM from 'react-dom'
//
import {BrowserRouter} from 'react-router-dom'
//引入App
import App from './App'
ReactDOM.render(
<BrowserRouter>
<App/>
</BrowserRouter>,
document.getElementById('root')
)
运行结果:
2.3 NavLink的使用
- NavLink组件
- NavLink组件和Link组件的功能是一致的,区别在于可以判断其to属性是否是当前匹配到的路由
- NavLink可以实现路由链接的高亮,通过activeClassName指定样式名,这里的Link或NavLink类似于Vue中的Router-link。
代码片段:(为节省空间,该案例Home、About、index的代码和上述第一个案例一致,不在重复描述):
App.js
import React, { Component } from 'react'
import {NavLink,Route} from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接,可以通过activeClassName自定义选中样式,如果不设置,就使用默认样式 */}
<NavLink activeClassName="mystyle" className="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="mystyle" className="list-group-item" to="/home">Home</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>react脚手架</title>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="/css/bootstrap.css">
<style>
/* 设置样式 */
.mystyle {
background-color: rgb(209, 137, 4) !important;
color: white !important;
}
</style>
</head>
<body>
<div id="root"></div>
</body>
</html>
运行结果:
2.4 封装自己的NavLink
代码片段(为节省空间,该案例Home、About、index的代码和上述第一个案例一致,不在重复描述):
App.jsx
import React, { Component } from 'react'
import {Route} from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接 ,标签内部数据,子组件也可以通过props接收*/}
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
MyNavLink.jsx
import React, { Component } from 'react'
import {NavLink} from 'react-router-dom'
export default class MyNavLink extends Component {
render() {
console.log(this.props);
return (
<NavLink activeClassName="mystyle" className="list-group-item" {...this.props}/>
)
}
}
运行结果:
2.5 Switch的使用
- Switch组件
1.通常情况下,path和component是一一对应的关系。
2.Switch可以提高路由匹配效率(单一匹配)。
3.Switch功能上类似于Vue中的Router-view。将来匹配到的路由组件将会被加载到Switch所在的位置。Switch组件内部存放Route组件。
代码片段(为节省空间,该案例MyNavLink.jsx、Home、About、index的代码和上述第三个案例一致,不在重复描述):
App.js
import React, { Component } from 'react'
import {Route,Switch} from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
import MyNavLink from './components/MyNavLink'
import Test from './pages/Test'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 ,当路由匹配中出现两个一样的路径时,使用Switch后只会匹配第一个*/}
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/home" component={Test}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
Test.jsx
import React, { Component } from 'react'
export default class Test extends Component {
render() {
return (
<div>
<h2>Test....</h2>
</div>
)
}
}
运行结果:
不使用Switch前:
使用后:
2.6 解决多级路径刷新页面样式丢失的问题
1.public/index.html 中 引入样式时不写 ./ 写 / (常用)
2.public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用)
3.使用HashRouter
代码片段(为节省空间,该案例MyNavLink.jsx、Home、About、index的代码和上述第三个案例一致,不在重复描述):
App.js
import React, { Component } from 'react'
import {Route,Switch} from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接,使用多级路径 */}
<MyNavLink to="/api/about">About</MyNavLink>
<MyNavLink to="/atguigu/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Switch>
<Route path="/api/about" component={About}/>
<Route path="/api/home" component={Home}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>react脚手架</title>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="/css/bootstrap.css">
<style>
/* 设置样式 */
.mystyle {
background-color: rgb(209, 137, 4) !important;
color: white !important;
}
</style>
</head>
<body>
<div id="root"></div>
</body>
</html>
运行结果:
修改前:
修改后:
2.7 路由的严格匹配与模糊匹配
1.默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致,就可以转跳)
2.开启严格匹配:<Route exact={true} path="/about" component={About}/>
3.严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
代码片段(为节省空间,该案例MyNavLink.jsx、Home、About、index的代码和上述第三个案例一致,不在重复描述):
App.js
import React, { Component } from 'react'
import {Route,Switch} from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home/a/b">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Switch>
<Route exact path="/about" component={About}/>
<Route exact path="/home" component={Home}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
运行结果:
模糊匹配:
精准匹配:
2.8 Redirect的使用
1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
2.具体编码:
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
代码片段(为节省空间,该案例MyNavLink.jsx、Home、About、index的代码和上述第三个案例一致,不在重复描述):
App.js
import React, { Component } from 'react'
import {Route,Switch,Redirect} from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件
import MyNavLink from './components/MyNavLink'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<Header/>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
运行结果:
三、路由组件与一般组件的区别
1.写法不同:
- 一般组件:
<Demo/>
- 路由组件:
<Route path="/demo" component={Demo}/>
2.存放位置不同:
- 一般组件:components
- 路由组件:pages
3.接收到的props不同:
- 一般组件:写组件标签时传递了什么,就能收到什么
- 路由组件:接收到三个固定的属性
-
history:
go: ƒ go(n) goBack: ƒ goBack() goForward: ƒ goForward() push: ƒ push(path, state) replace: ƒ replace(path, state)
-
location:
pathname: "/about" search: "" state: undefined
-
match:
params: {} path: "/about" url: "/about"
-
代码片段(为节省空间,该案例MyNavLink.jsx、App、Home、index的代码和上述第三个案例一致,不在重复描述):
Header.jsx(一般组件):
import React, { Component } from 'react'
export default class Header extends Component {
render() {
console.log('Header组件收到的props是',this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
)
}
}
About.jsx(路由组件):
import React, { Component } from 'react'
export default class About extends Component {
render () {
console.log('About组件收到的props是', this.props);
return (
<h3>我是About的内容</h3>
)
}
}
运行结果: