第五章 React 路由
一、相关理解
1. SPA 的理解
- 单页 Web 应用(single page web application,SPA)。
- 整个应用只有一个完整的页面。
- 点击页面中的链接不会刷新页面,只会做页面的局部更新。
- 数据都需要通过 ajax 请求获取, 并在前端异步展现。
2. 路由的理解
2.1 什么是路由?
- 一个路由就是一个映射关系(key:value)
- key 为路径, value 可能是 function 或 component
2.2 路由分类
2.2.1 后端路由
- 理解: value 是 function, 用来处理客户端提交的请求。
- 注册路由: router.get(path, function(req, res))
- 工作过程:当 node 接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
2.2.2 前端路由
- 浏览器端路由,value 是 component,用于展示页面内容。
- 注册路由: <Route path=“/test” component={Test}>
- 工作过程:当浏览器的 path 变为/test 时, 当前路由组件就会变为 Test 组件
3. react-router-dom 的理解
- react 的一个插件库。
- 专门用来实现一个 SPA 应用。
- 基于 react 的项目基本都会用到此库。
二、react-router-dom 相关 API
1. 内置组件
- <BrowserRouter>
- <HashRouter>
- <Route>
- <Redirect>
- <Link>
- <NavLink>
- <Switch>
2. 其它
- history 对象
- match 对象
- withRouter 函数
三、基本路由使用
1. 效果
2. 准备
2.1 下载 react-router-dom
- npm install --save react-router-dom
2.2 引入 bootstrap.css:
- <link rel=“stylesheet” href=“/css/bootstrap.css”>
2.3 注意
- 由于 react-router-dom 在 2021 年 11 月份升级到了 6 版本,此处是 5 版本的代码展示,需要执行:
npm i react-router-dom@5
- 最新的 6 版本使用会在后续更新
3. 代码 - 路由的基本使用
3.1 index.js
/* src/index.js */
//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
//引入App组件
import App from "./App";
//渲染App到页面
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
3.2 App
/* src/App.jsx */
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 active" href="./about.html">
About
</a>
<a className="list-group-item" 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>
);
}
}
3.3 Home
/* src/components/Home/index.jsx */
import React, { Component } from 'react'
export default class index extends Component {
render() {
return (
<h3>我是Home的内容</h3>
)
}
}
3.4 About
/* src/components/About/index.jsx */
import React, { Component } from 'react'
export default class index extends Component {
render() {
return (
<h3>我是About的内容</h3>
)
}
}
3.5 总结
1.明确好界面中的导航区、展示区
2.导航区的a标签改为Link标签
<Link to="/xxxxx">Demo</Link>
3.展示区写Route标签进行路径的匹配
<Route path='/xxxx' component={Demo}/>
4.<App>的最外侧包裹了一个<BrowserRouter>或<HashRouter>
4. 代码 - 路由组件与一般组件
4.1 App
/* src/App.jsx */
import React, { Component } from "react";
import { Link, 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">
<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>
);
}
}
4.2 Header
/* src/components/Header/index.jsx */
import React, { Component } from "react";
export default class index extends Component {
render() {
return (
<div className="page-header">
<h2>React Router Demo</h2>
</div>
);
}
}
4.3 About
/* src/pages/About/index.jsx */
import React, { Component } from 'react'
export default class index extends Component {
render() {
console.log('About组件收到的props是', this.props);
return (
<h3>我是About的内容</h3>
)
}
}
4.4 总结
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"
5. 代码 - NavLink 的使用
5.1 App
/* src/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是一般组件
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">
<NavLink activeClassName="alex" className="list-group-item" to="/about">
About
</NavLink>
<NavLink activeClassName="alex" 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>
);
}
}
5.2 index.html
<!-- public/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React App</title>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="/css/bootstrap.css">
<style>
.alex{
background-color: rgb(209, 137, 4) !important;
color: white !important;
}
</style>
</head>
<body>
<div id="root"></div>
</body>
</html>
6. 代码 - 封装 NavLink 组件
6.1 App
/* src/App.jsx */
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是一般组件
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">
{/* 注册路由 */}
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
</div>
</div>
</div>
</div>
</div>
);
}
}
6.2 MyNavLink
/* src/components/MyNavLink/index.jsx */
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
export default class MyNavLink extends Component {
render() {
return (
<NavLink activeClassName="alex" className="list-group-item" {...this.props}/>
);
}
}
6.3 总结
1.NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
2.标签体内容是一个特殊的标签属性
3.通过this.props.children可以获取标签体内容