React应用(基于React脚手架)
使用create-react-app创建react应用
react脚手架
xxx脚手架:用来帮助程序员快速创建一个基于xxx库的模板项目。
-
① 包含了所有需要的配置(语法检查、jsx编译、devServer、……)。 -
② 下载好了所有相关的依赖。 -
③ 可以直接运行一个简单效果。
react提供了一个用于创建react项目的脚手架库:create-react-app
。
项目的整体技术架构为:react + webpack + es6 + eslint
。
使用脚手架开发项目的特点:模块化、组件化、工程化。
创建项目并启动
全局安装:
npm -g install create-react-app
切换到你想创建项目的目录:
create-react-app hello-react
进入项目文件夹:
cd hello-react
启动项目:
npm run start
react脚手架项目结构
public:静态资源文件夹。
-
favicon.icon:网站页签图标。 -
index.html:主页面。
-
logo192.png:logo图片。 -
logo521.png:logo图片。 -
manifest.json:应用加壳的配置文件。 -
robots.txt:爬虫协议文件。
src:源代码文件夹。
-
App.css:APP组件的样式。 -
App.js:APP组件。 -
App.text.js:用于给APP做测试。 -
index.css:样式。 -
index.js:入口文件。
-
logo.svg:logo图片。 -
reportWebVitals.js:页面性能分析文件(需要web-vitals库的支持)。 -
setupTests.js:组件单元测试的文件(需要jest-dom库的支持)。
功能界面的组件化编码流程(通用)
① 拆分组件:拆分界面,抽取组件。
② 实现静态组件:使用组件实现静态页面效果。
③ 实现动态组件:
-
动态组件初始化数据。
-
数据类型。 -
数据名称。 -
保存在哪个组件? -
交互(从绑定事件监听开始)。
组件化编码
项目结构

创建组件
新建Hello组件
index.module.css
.title {
background-color: orange;
}
index.jsx
import React, {Component} from "react";
import hello from './index.module.css'
export default class Hello extends Component {
render() {
return (
<h2 className={hello.title}>Hello React(*^▽^*)</h2>
);
}
}
新建Welcome组件
index.module.css
.title {
background-color: skyblue;
}
index.jsx
import React, {Component} from "react";
import welcome from './index.module.css'
export default class Welcome extends Component {
render() {
return (
<h2 className={welcome.title}>Welcome</h2>
);
}
}
APP组件
App.jsx
import React, {Component} from "react";
import Hello from "./components/Hello"
import Welcome from "./components/Welcome"
//创建并暴露APP组件
export default class App extends Component {
render() {
return (
<div>
<Hello/>
<Welcome/>
</div>
);
}
}
index.js(入口文件)
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入APP组件
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
其他文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<!-- %PUBLIC_URL%代表public文件夹的路径 -->
<link href="%PUBLIC_URL%/favicon.ico" rel="icon"/>
<!-- 用于开启理想视口,用于做移动端网页的适配 -->
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<!-- 用于配置浏览器页签+地址栏的颜色(仅支持Android手机浏览器) -->
<meta content="#000000" name="theme-color"/>
<meta content="Web site created using create-react-app" name="description"/>
<!-- 用于指定网页添加到手机主屏幕后的图标 -->
<link href="%PUBLIC_URL%/logo192.png" rel="apple-touch-icon"/>
<!-- 应用加壳的配置文件 -->
<link href="%PUBLIC_URL%/manifest.json" rel="manifest"/>
<title>React App</title>
</head>
<body>
<!-- 如果浏览器不支持JS,则展示标签中的内容。 -->
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
package.json
{
"name": "hello-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.12.0",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
React ajax
前置说明
React本身只关注界面,并不包含发送ajax请求的代码。
前端应用需要通过ajax和后台进行交互(JSON数据)。
React应用中需要集成第三方ajax库(或自己封装)。
常用的ajax请求库
JQuery:比较重,如果需要另外引入,不建议使用。
axios:轻量级,建议使用。
-
封装XMLHttpRequest对象的ajax。 -
Promise风格。 -
可以用在浏览器端和node服务器端。
axios
官网
https://github.com/axios/axios。
安装
安装axios:
yarn add axios
axios的一些API
发送GET请求:
axios.get(url[,config]);
发送POST请求:
axios.post(url,data[,config]);
脚手架配置代理
方法1
假设客户端是http://localhost:3000,而服务器是http://localhost:5000。
浏览器有同源策略的限制,当我们的客户端和服务器只要协议、域名、端口一个不同,就不能接收到服务器传递的数据,脚手架中的package.json中配置代理(配置完重启一下,会开启一个代理服务器)。

package.json:
{
"name": "react-ajax",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.12.0",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"axios": "^0.21.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"proxy": "http://localhost:5000"
}
发送请求的时候,将请求发送给http://localhost:3000,由代理给我们将请求发送给http://localhost:5000。
import React, {Component} from 'react';
import './APP.css'
import axios from "axios";
export default class App extends Component {
//获取学生数据的回调
getStudentData = () => {
axios.get("http://localhost:3000/students")
.then(response => {
console.log('成功了', response.data);
}, error => {
console.log('失败了', error);
})
}
render() {
return (
<div>
<button onClick={this.getStudentData}>点我获取学生数据</button>
</div>
);
}
}
注意:
此种方式是将public作为devServer的根路径,如果端口为3000的服务器没有数据,才将请求转发给5000端口的服务器,否则直接从3000端口的服务器获取。
这种方式太单一了,只能代理一个服务器。
方法2
在项目的src目录下新建一个名为setupProxy.js的文件,React脚手架会自动读取该文件,需要重启项目。
setupProxy.js的内容如下:
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
//服务器代理
proxy('/api1', { //遇见/api1前缀的请求,就会触发该代理配置
target: 'http://localhost:5000',
changeOrigin: true, //控制服务器收到的请求头中Host字段的值
//发送请求时,请求路径重写:将/api1/xxx --> xxx(去掉/api1)
pathRewrite: {
'^/api1': ''
}
}),
proxy('/api2', {
target: 'http://localhost:5001',
changeOrigin: true,
//发送请求时,请求路径重写:将/api1/xxx --> xxx(去掉/api1)
pathRewrite: {
'^/api2': ''
}
})
)
}
消息订阅发布机制
概述
父子组件通过props进行通信。
兄弟组件通过pubsub(发布订阅)进行通信,当前也可以用于任意组件之间的通信。
5.2 使用
工具库:PubSubJS。
安装:
yarn add pubsub-js
使用:
import PubSub from 'pubsub-js'
PubSub.subscribe('消息名',(msg,data)=>{}); //订阅
PubSub.publish('消息名',{}); //发布消息
Fetch(扩展)
文档
https://github.github.io/fetch/
特点
fetch:原生函数,不再使用XMLHttpRequest对象提交Ajax请求。
老版本的浏览器可能不支持。
相关API
GET请求:
fetch(url).then(function(response) {
return response.json()
}).then(function(data) {
console.log(data)
}).catch(function(e) {
console.log(e)
});
POST请求:
fetch(url, {
method: "POST",
body: JSON.stringify(data),
}).then(function(data) {
console.log(data)
}).catch(function(e) {
console.log(e)
})
React路由
相关理解
SPA的理解
单页Web应用(Single Page Application,SPA)。
整个应用只有一个完整的页面。
点击页面中的链接不会刷新页面,只会做页面的局部更新。
数据都需要通过ajax请求获取,并在前端异步展现。
路由的理解
什么是路由?
一个路由就是一个映射关系(key:value)。
key为路径,value可能是function或component。
路由的分类
后端路由:
-
理解:value是function,用来处理客户端提交的请求。 -
注册路由:
router.get(path,function(req,resp)=>{})
工作过程:当Node接收到一个请求的时候,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。
前端路由:
-
浏览器端路由,value是component,用于展示页面。 -
注册路由:
<Route path="/test" component={Test}>
工作过程:当浏览器的path变为/test的时候,当前路由组件就变为Test组件。
react-router-dom的理解
React的一个插件库。
专门用来实现一个SPA应用。
基于React的项目基本上都会使用此库。
react-router-dom相关API
内置组件
-
<BrowserRouter>
-
<HashRouter>
-
<Route>
-
<Redirect>
-
<Link>
-
<NavLink>
-
<Switch>
其它
-
history对象 -
match对象。 -
withRouter函数。
路由的基本使用
准备工作
安装react-router-dom:
yarn add react-router-dom
在index.html页面中引入bootstrap.css
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" />
目录结构:

使用步骤
① 明确好界面中的导航区、展示区。
② 导航区的a标签改为Link标签。
<Link to="/xxx">Demo</Link>
③ 展示区写Route标签进行路径的匹配。
<Route path="/xxx" component={Demo}/>
④ <APP/>
的最外侧包裹了一个<BrowserRouter>
或<HashRouter>
。
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
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" 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>
);
}
}
components/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
return (
<h3>我是Home的内容</h3>
);
}
}
components/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
);
}
}
路由组件和一般组件
区别
① 写法不同:
-
一般组件:
<Home/>
-
路由组件:
<Route path="/home" component={Home}/>
② 存放的位置不同:
-
一般组件:components。 -
路由组件:pages。
③ 接收到的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"
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
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">
{/* 原生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>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
console.log("Header",this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
console.log("Home",this.props);
return (
<h3>我是Home的内容</h3>
);
}
}
概述
NavLink可以实现路由链接的高亮,通过activeClassName指定样式名。
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {Route, NavLink} 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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" 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>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
console.log("Header",this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
console.log("Home",this.props);
return (
<h3>我是Home的内容</h3>
);
}
}
概述
上面NavLink的案例中,如果路由链接越来越多的话,那么就会出现代码膨胀,后期维护也困难,我们将NavLink封装成组件,方便复用。
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在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>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
console.log("Home",this.props);
return (
<h3>我是Home的内容</h3>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
console.log("Header",this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
components/MyNavLink/index.jsx
import React, {Component} from 'react';
import {NavLink} from 'react-router-dom';
export default class MyNavLink extends Component {
render() {
return (
<NavLink className="list-group-item" activeClassName="active" {...this.props}/>
);
}
}
Switch
概述
通常情况下,path和component是一一对应的。
Switch可以提高路由匹配效率(单一匹配),只要匹配到了,就不会继续向下匹配。
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
App.jsx
import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header";
import Test from "./pages/Test"; //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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
console.log("Home",this.props);
return (
<h3>我是Home的内容</h3>
);
}
}
pages/Test/index.jsx
import React, {Component} from 'react';
export default class Test extends Component {
render() {
return (
<div>
Test...
</div>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
console.log("Header",this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
解决多级路径刷新页面样式丢失问题
概述
多级路径刷新页面样式丢失问题:
默认情况下,webpack
会将public
目录作为根目录,假设devServer
的的地址为http://localhost:3000
,路由为/xudaxian/home
,我们平常使用./
等相对路径来书写样式路径。
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8"/>
<!-- %PUBLIC_URL%代表public文件夹的路径 -->
<link href="favicon.ico" rel="icon"/>
<!-- 用于开启理想视口,用于做移动端网页的适配 -->
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<title>解决样式丢失问题</title>
<link href="./css/bootstrap.css" rel="stylesheet">
</head>
<body>
<!-- 如果浏览器不支持JS,则展示标签中的内容。 -->
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
① 项目启动的时候,webpack
会启动devServer
,打开浏览器,并访问http://localhost:3000
,其实webpack
就会去public
目录中寻找index.htm
l,而bootstrap.css
的路径设置的是./css/bootstrap.css
,所以webpack
会去public
的目录中寻找css
目录下是否有bootstrap.css
,如果有,就返回此样式文件;如果没有,就返回index.html
。
② 此时,我们点击路由/xudaxian/home
,因为不会刷新页面,所以样式不会丢失。
import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/xudaxian/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/xudaxian/home">Home</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
{/* Switch可以提高路由匹配效率(单一匹配) */}
<Switch>
<Route path="/xudaxian/about" component={About}/>
<Route path="/xudaxian/home" component={Home}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
③ 此时,我们刷新了浏览器,webpack
会将/xudaxian
也作为样式路径的一部分,即http://localhost:3000/xudaxian/css/bootstrap.css
,但是public
目录中是没有xudaxian
目录的,更何况css/bootstrap.css
文件,所以,因为找不到对应的样式文件,就返回index.html
。
解决方案:
-
① pubilc/index.html中引入样式的时候,不写./,而写/(常用)。 -
② pubilc/index.html中引入样式的时候,不写./,而写%PUBLIC_URL%(常用)。 -
③ 使用HashRouter。
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {HashRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<HashRouter>
<App/>
</HashRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/xudaxian/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/xudaxian/home">Home</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 注册路由 */}
{/* Switch可以提高路由匹配效率(单一匹配) */}
<Switch>
<Route path="/xudaxian/about" component={About}/>
<Route path="/xudaxian/home" component={Home}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
return (
<h3>我是Home的内容</h3>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
路由的模糊匹配和严格匹配
概述
默认使用的是模糊匹配(要求:【输入的路径】必须要包含【匹配的路径】,且顺序要一致)。
开启严格匹配:
<Route exact={true} path="/about" component={About}/>
严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由。
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home/a/b">Home</NavLink>
</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}/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
console.log("Home",this.props);
return (
<h3>我是Home的内容</h3>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
console.log("Header",this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
Redirect的使用
概述
一般写在路由注册的最下方,当所有路由都无法匹配的时候,跳转到Redirect指定的路由。
具体编码:
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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}/>
{/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
export default class Home extends Component {
render() {
console.log("Home",this.props);
return (
<h3>我是Home的内容</h3>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
console.log("Header",this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
嵌套路由
概述
注册子路由的时候要写上父路由的path值。
路由的匹配时按照注册路由的顺序进行的。
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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}/>
{/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
import {NavLink, Route, Switch,Redirect} from 'react-router-dom';
import News from './News';
import Message from './Message';
export default class Home extends Component {
render() {
console.log("Home", this.props);
return (
<div>
<h3>我是Home的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
</li>
<li>
<NavLink className="list-group-item" activeClassName="active"
to="/home/message">Message</NavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
</div>
</div>
);
}
}
pages/Home/News/index.jsx
import React, {Component} from 'react';
export default class News extends Component {
render() {
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
);
}
}
pages/Home/Message/index.jsx
import React, {Component} from 'react';
export default class Message extends Component {
render() {
return (
<ul>
<li>
message001
</li>
<li>
message002
</li>
<li>
message003
</li>
</ul>
);
}
}
component/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
console.log("Header",this.props);
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
向路由组件传递参数
向路由组件传递params参数
概述
路由链接(携带参数):
<Link to={"/demo/test/tom/18"}>详情</Link>
注册路由(声明接收):
<Route path="/demo/test/:name/:id" component={Detail}/>
接收参数:
this.props.match.params
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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}/>
{/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
console.log("About",this.props);
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';
export default class Home extends Component {
render() {
return (
<div>
<h3>我是Home的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
</li>
<li>
<NavLink className="list-group-item" activeClassName="active"
to="/home/message">Message</NavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
</div>
</div>
);
}
}
pages/Homes/News/index.jsx
import React, {Component} from 'react';
export default class News extends Component {
render() {
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
);
}
}
pages/Homes/Message/index.jsx
import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";
export default class Message extends Component {
render() {
return (
<div>
<ul>
<li>
{/* 向路由组件传递params参数 */}
<Link to={"/home/message/detail/1/message001"}>message001</Link>
</li>
<li>
<Link to={"/home/message/detail/2/message002"}>message002</Link>
</li>
<li>
<Link to={"/home/message/detail/3/message003"}>message003</Link>
</li>
</ul>
<hr/>
<Switch>
{/* 声明接收params参数 */}
<Route path="/home/message/detail/:id/:title" component={Detail}/>
</Switch>
</div>
);
}
}
pages/Homes/Message/Detail/index.jsx
import React, {Component} from 'react';
export default class Detail extends Component {
render() {
//接收params参数
const {id, title} = this.props.match.params;
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>CONTENT:你好,中国。</li>
</ul>
);
}
}
向路由组件传递search参数
概述
路由链接(携带参数):
<Link to={"/demo/test/?name=tom&age=18"}>详情</Link>
注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Detail}/>
接收参数:
this.props.location.search
注意:
获取到的search是urlencoded编码的字符串,需要借助querystring解析。
React内部已经安装好了querystring。
使用:
import querystring from 'querystring';
querystring.parse();
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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}/>
{/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';
export default class Home extends Component {
render() {
return (
<div>
<h3>我是Home的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
</li>
<li>
<NavLink className="list-group-item" activeClassName="active"
to="/home/message">Message</NavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
</div>
</div>
);
}
}
pages/Home/News/index.jsx
import React, {Component} from 'react';
export default class News extends Component {
render() {
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
);
}
}
pages/Home/Message/index.jsx
import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";
export default class Message extends Component {
render() {
return (
<div>
<ul>
<li>
{/* 向路由组件传递search参数 */}
<Link to={"/home/message/detail/?id=1&title='message001'"}>message001</Link>
</li>
<li>
<Link to={"/home/message/detail/?id=1&title='message002'"}>message002</Link>
</li>
<li>
<Link to={"/home/message/detail/?id=1&title='message003'"}>message003</Link>
</li>
</ul>
<hr/>
<Switch>
{/* 声明接收search参数,无需声明,正常注册即可 */}
<Route path="/home/message/detail/" component={Detail}/>
</Switch>
</div>
);
}
}
pages/Home/Message/Detail/index.jsx
import React, {Component} from 'react';
import qs from 'querystring';
export default class Detail extends Component {
render() {
const {search} = this.props.location;
const {id,title} = qs.parse(search.slice(1));
//接收params参数
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>CONTENT:你好,中国。</li>
</ul>
);
}
}
向路由组件传递state参数
概述
路由链接(携带参数):
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Detail}/>
接收参数:
this.props.location.state
注意:刷新也可以保留住参数。
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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}/>
{/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';
export default class Home extends Component {
render() {
return (
<div>
<h3>我是Home的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
</li>
<li>
<NavLink className="list-group-item" activeClassName="active"
to="/home/message">Message</NavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
</div>
</div>
);
}
}
pages/Home/News/index.jsx
import React, {Component} from 'react';
export default class News extends Component {
render() {
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
);
}
}
pages/Home/Message/index.jsx
import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";
export default class Message extends Component {
render() {
return (
<div>
<ul>
<li>
{/* 向路由组件传递search参数 */}
<Link to={{pathname:'/home/message/detail',state:{id:1,title:'message001'}}}>message001</Link>
</li>
<li>
<Link to={{pathname:'/home/message/detail',state:{id:1,title:'message002'}}}>message002</Link>
</li>
<li>
<Link to={{pathname:'/home/message/detail',state:{id:1,title:'message003'}}}>message003</Link>
</li>
</ul>
<hr/>
<Switch>
{/* 声明接收search参数,无需声明,正常注册即可 */}
<Route path="/home/message/detail/" component={Detail}/>
</Switch>
</div>
);
}
}
pages/Home/Message/Detail/index.jsx
import React, {Component} from 'react';
export default class Detail extends Component {
render() {
const {id,title} = this.props.location.state || {};
//接收params参数
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>CONTENT:你好,中国。</li>
</ul>
);
}
}
components/Header/index.jsx
import React, {Component} from 'react';
export default class Header extends Component {
render() {
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
总结路由参数
向路由组件传递params参数
路由链接(携带参数):
<Link to={"/demo/test/tom/18"}>详情</Link>
注册路由(声明接收):
<Route path="/demo/test/:name/:id" component={Detail}/>
接收参数:
this.props.match.params
向路由组件传递search参数
路由链接(携带参数):
<Link to={"/demo/test/?name=tom&age=18"}>详情</Link>
注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Detail}/>
接收参数:
this.props.location.search
备注:获取到的search是urlencoded编码的字符串,需要借助querystring解析。
向路由组件传递state参数
路由链接(携带参数):
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Detail}/>
接收参数:
this.props.location.state
编程式路由导航
概述
借助 this.props.history 对象上的API操作路由跳转、前进、后退等。
this.props.history.push()
this.props.history.replace()
this.props.history.goBack()
this.props.history.goForward()
this.props.history.go()
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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}/>
{/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';
export default class Home extends Component {
render() {
return (
<div>
<h3>我是Home的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
</li>
<li>
<NavLink className="list-group-item" activeClassName="active"
to="/home/message">Message</NavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
</div>
</div>
);
}
}
pages/Home/News/index.jsx
import React, {Component} from 'react';
export default class News extends Component {
render() {
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
);
}
}
pages/Home/Message/index.jsx
import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";
export default class Message extends Component {
replaceShow = (id,title) => {
//replace跳转+携带params参数
this.props.history.replace(`/home/message/detail/${id}/${title}`);
}
pushShow = (id,title) => {
//push跳转+携带params参数
this.props.history.push(`/home/message/detail/${id}/${title}`);
}
forward = () => {
this.props.history.goForward();
}
back = () => {
this.props.history.goBack();
}
render() {
return (
<div>
<ul>
<li>
{/* 向路由组件传递params参数 */}
<Link to={"/home/message/detail/1/message001"}>message001</Link>
<button onClick={()=>this.pushShow(1,'message001')}>push查看</button>
<button onClick={()=>this.replaceShow(1,'message001')}>replace查看</button>
</li>
<li>
<Link to={"/home/message/detail/2/message002"}>message002</Link>
<button onClick={()=>this.pushShow(2,'message002')}>push查看</button>
<button onClick={()=>this.replaceShow(2,'message002')}>replace查看</button>
</li>
<li>
<Link to={"/home/message/detail/3/message003"}>message003</Link>
<button onClick={()=>this.pushShow(3,'message003')}>push查看</button>
<button onClick={()=>this.replaceShow(3,'message003')}>replace查看</button>
</li>
</ul>
<hr/>
<Switch>
{/* 声明接收params参数 */}
<Route path="/home/message/detail/:id/:title" component={Detail}/>
</Switch>
<button onClick={this.back}>后退</button>
<button onClick={this.forward}>前进</button>
</div>
);
}
}
pages/Home/Message/Detail/index.jsx
import React, {Component} from 'react';
export default class Detail extends Component {
render() {
//接收params参数
const {id, title} = this.props.match.params;
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>CONTENT:你好,中国。</li>
</ul>
);
}
}
components/Header/index.js
import React, {Component} from 'react';
export default class Header extends Component {
render() {
return (
<div className="page-header"><h2>React Router Demo</h2></div>
);
}
}
withRouter的使用
概述
withRouter函数让一般组件拥有路由组件的三个固定属性:
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"
准备工作
目录结构:

应用示例
示例:
index.js
//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
APP.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'; //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/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">
{/* 原生HTML中,靠<a>标签跳转不同的页面 */}
{/*
<a className="list-group-item" href="./about.html">About</a>
<a className="list-group-item active" href="./home.html">Home</a>
*/}
{/* 在React中,靠路由链接实现切换组件---编写路由链接 */}
<NavLink className="list-group-item" activeClassName="active" to="/about">About</NavLink>
<NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
</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}/>
{/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
<Redirect to="/about"/>
</Switch>
</div>
</div>
</div>
</div>
</div>
);
}
}
pages/About/index.jsx
import React, {Component} from 'react';
export default class About extends Component {
render() {
return (
<h3>我是About的内容</h3>
);
}
}
pages/Home/index.jsx
import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';
export default class Home extends Component {
render() {
return (
<div>
<h3>我是Home的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
</li>
<li>
<NavLink className="list-group-item" activeClassName="active"
to="/home/message">Message</NavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/message" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
</div>
</div>
);
}
}
pages/Home/Message/index.jsx
import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";
export default class Message extends Component {
replaceShow = (id,title) => {
//replace跳转+携带params参数
this.props.history.replace(`/home/message/detail/${id}/${title}`);
}
pushShow = (id,title) => {
//push跳转+携带params参数
this.props.history.push(`/home/message/detail/${id}/${title}`);
}
forward = () => {
this.props.history.goForward();
}
back = () => {
this.props.history.goBack();
}
render() {
return (
<div>
<ul>
<li>
{/* 向路由组件传递params参数 */}
<Link to={"/home/message/detail/1/message001"}>message001</Link>
<button onClick={()=>this.pushShow(1,'message001')}>push查看</button>
<button onClick={()=>this.replaceShow(1,'message001')}>replace查看</button>
</li>
<li>
<Link to={"/home/message/detail/2/message002"}>message002</Link>
<button onClick={()=>this.pushShow(2,'message002')}>push查看</button>
<button onClick={()=>this.replaceShow(2,'message002')}>replace查看</button>
</li>
<li>
<Link to={"/home/message/detail/3/message003"}>message003</Link>
<button onClick={()=>this.pushShow(3,'message003')}>push查看</button>
<button onClick={()=>this.replaceShow(3,'message003')}>replace查看</button>
</li>
</ul>
<hr/>
<Switch>
{/* 声明接收params参数 */}
<Route path="/home/message/detail/:id/:title" component={Detail}/>
</Switch>
<button onClick={this.back}>后退</button>
<button onClick={this.forward}>前进</button>
</div>
);
}
}
pages/Home/Message/Detail/index.jsx
import React, {Component} from 'react';
export default class Detail extends Component {
render() {
//接收params参数
const {id, title} = this.props.match.params;
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>CONTENT:你好,中国。</li>
</ul>
);
}
}
pages/Home/News/index.jsx
import React, {Component} from 'react';
export default class News extends Component {
// componentDidMount() {
// setTimeout(() => {
// this.props.history.push('/home/message');
// }, 2000)
// }
render() {
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
);
}
}
component/Header/index.jsx
import React, {Component} from 'react';
import {withRouter} from 'react-router-dom'
class Header extends Component {
forward = () => {
this.props.history.goForward();
}
back = () => {
this.props.history.goBack();
}
render() {
console.log(this.props);
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={this.back}>后退</button>
<button onClick={this.forward}>前进</button>
</div>
);
}
}
export default withRouter(Header);
//withRouter可以加工一般组件,让一般组件具备路由组件特有的API。
//withRouter的返回值是一个新组件
BrowserRouter和HashRouter的区别
底层原理不一样
BrowserRouter使用的是H5的History API,不兼容IE9及以下版本。
HashRouter使用的是URL的哈希值。
path表现形式不一样
BrowserRouter的路径中没有#
,例如:http://localhost:3000/demo/test
。
HashRouter的路径中包含#
,例如:http://localhost:3000/#/demo/test
。
刷新后对路由state参数的影响
BrowserRouter没有任何影响,因为state保存在History对象之中。
HashRouter刷新后会导致路由state参数的丢失。
备注
HashRouter可以用于解决一些路径错误相关的问题。
原文始发于微信公众号(程序员阿晶):React高级部分(一)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/19895.html