一、axios: 轻量级
- 封装XmlHttpRequest对象的ajax
- 可以用在浏览器端和node服务器端
- promise风格
1.1 axios的应用
- 初始化react脚手架
npm create react-app react_ajax
- 下载axios库
npm i axios
- App.js改成App.jsx,并导入axios
import "./App.css"
import React, { Component } from "react"
import axios from "axios"
export default class App extends Component {
getStudentData = () => {
axios
//并不是素有请求都转给5000,3000里没有再转发,有就用当前的
.get("/api1/students")
.then((res) => {
console.log(res.data)
})
}
getCarData = () => {
axios
.get("/api2/cars")
.then((res) => {
console.log(res.data)
})
}
render() {
return (
<div className="App">
<button onClick={this.getStudentData}>获取学生数据</button>
<br />
<button onClick={this.getCarData}>获取汽车数据</button>
</div>
)
}
}
- App.css添加
button {
margin-top: 20px;
padding: 4px 12px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
text-align: center;
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),
0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;
color: #fff;
background-color: #da4f49;
border: 1px solid #bd362f;
}
1.1.1 案例 点击按钮访问server1,server2里的数据
server1: http://localhost:5000/students
server2: http://localhost:5001/cars
注意
不同端口的两个数据,涉及跨域问题可考虑代理
测试代理服务源码: https://download.csdn.net/download/weixin_42152058/87751751
只有一个代理
在package.json中追加配置
"proxy":"http://localhost:5000"
多个代理
在react_ajax的src文件夹下创建 setupProxy.js ,React会自动识别
//多个代理
const { createProxyMiddleware } = require("http-proxy-middleware")
module.exports = function (app) {
app.use(
createProxyMiddleware("/api1", {
target: "http://localhost:5000",
changeOrigin: true,
pathRewrite: {
"^/api1": "",
},
}),
createProxyMiddleware("/api2", {
target: "http://localhost:5001",
changeOrigin: true,
pathRewrite: {
"^/api2": "",
},
})
)
}
注意:其实就是中间件的使用 app.use()
- "/api1":含有"/api1"前缀的请求
- target: 请求转发给谁
- changeOrigin :控制服务器收到的响应头 Host 字段的值
- 设置为true时,服务器收到的请求头中的host为:localhost:5000
- 设置为false时,服务器收到的请求头中的host为:localhost:3000
- 默认值为false,一般将changeOrigin值设为true
- pathRewrite :重写请求路径,就可以把 request.url /api1替换成空字符串 ,否则 就会把 /api1/students送给5000
1.1.2 案例 github搜索用户(props)
发送请求,返回github用户
请求地址: https://api.github.com/search/users?q=xxxxxx
为防止请求地址访问失败,模拟服务器
https://download.csdn.net/download/weixin_42152058/87751992
- 准备工作
1. 初始化reat_github_props项目
2. 设置代理,在src下新建setupProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware")
module.exports = function (app) {
app.use(
createProxyMiddleware("/api", {
target: "http://localhost:5000",
changeOrigin: true,
pathRewrite: {
"^/api": "",
},
})
)
}
3. 拆分组件
- Search组件
import React, { Component } from "react"
export default class Search extends Component {
render() {
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">搜索Github用户</h3>
<div>
<input
type="text"
placeholder="enter the name you search"
/>
<button>Search</button>
</div>
</section>
)
}
}
- Item组件
import React, { Component } from "react"
export default class Item extends Component {
render() {
return (
<div className="card">
<a
rel="noopener noreferrer"
href="https://github.com/reactjs"
target="_blank"
>
<img
alt="avatar"
src="https://img0.baidu.com/it/u=3869343912,2751914656&fm=253&fmt=auto&app=138&f=PNG?w=506&h=500"
style={{ width: "100px" }}
/>
</a>
<p className="card-text">reactjs</p>
</div>
)
}
}
- List组件
import React, { Component } from "react"
import Item from "../Item"
import "./index.css"
export default class List extends Component {
render() {
return (
<div className="row">
<Item />
</div>
)
}
}
.album {
min-height: 50rem; /* Can be removed; just added for demo purposes */
padding-top: 3rem;
padding-bottom: 3rem;
background-color: #f7f7f7;
}
.card {
float: left;
width: 33.333%;
padding: 0.75rem;
margin-bottom: 2rem;
border: 1px solid #efefef;
text-align: center;
}
.card > img {
margin-bottom: 0.75rem;
border-radius: 100px;
}
.card-text {
font-size: 85%;
}
- 引用bootstrap.css样式,放到public/css文件夹下
- index.html引入bootstrap.css
<link rel="stylesheet" href="./css/bootstrap.css"/>
- 事件准备
1. 引入axios
npm i axios
2. App组件初始化
//users初始化状态
state = {
users: [],
//是否为第一次打开
isFirst: true,
//是否处于加载中
isLoading: false,
err: false,
}
<div className="container">
<Search getData={this.getData} />
<List {...this.state} />
</div>
getData = (stateobj) => {
this.setState(stateobj)
}
3. 展示List组件
根据加载的状态对数据进行逐步展示,第一次加载,第二种:等待,第三种:数据加载成功, 第四种错误页
import React, { Component } from "react"
import Item from "../Item"
import "./index.css"
export default class List extends Component {
render() {
const { users, isFirst, isLoading, err } = this.props
return (
<div className="row">
{isFirst ? (
<h2>欢迎使用,输入关键字</h2>
) : isLoading ? (
<h2>正在加载......</h2>
) : err ? (
<h3 style={{ color: "red" }}>{err}</h3>
) : (
users.map((users) => {
return (
<Item
key={users.id}
{...users}
/>
)
})
)}
</div>
)
}
}
4. 获取search输入值,更新列表
<div>
<input
ref={(c) => (this.keyEl = c)}
type="text"
placeholder="enter the name you search"
/>
<button onClick={this.search}>Search</button>
</div>
search = () => {
const { getData } = this.props
//1. 获取用户输入
const {
keyEl: { value },
} = this
//发送请求前通知app更新状态
getData({ isFirst: false, isLoading: true })
//2. 发送请求
axios
.get(`/api/search/users?q=${value}`)
.then((res) => {
getData({ isLoading: false, users: res.data.items })
})
.catch((error) => {
getData({ isLoading: false, err: error.message})
})
}
二、消息订阅与发布机制(报纸订阅)
适用于任意组件通信
1. 先订阅再发布
2. 适用于任何组件通信
3. 要在组件的componentWillUnmount中取消订阅
- 下载工具库
npm install pubsub-js
Search组件
- 发布信息,PubSub.publish(消息名,数据)
import PubSub from "pubsub-js"
search = () => {
//1. 获取用户输入
const {
keyEl: { value },
} = this
//发布消息
PubSub.publish("sendMsg", { isFirst: false, isLoading: true })
//2. 发送请求
axios
.get(`/api/search/users?q=${value}`)
.then((res) => {
//请求成功通知List更新状态
PubSub.publish("sendMsg", { isLoading: false, users: res.data.items })
})
.catch((error) => {
PubSub.publish("sendMsg", { isLoading: false, err: error.message })
})
}
List组件
- 初始化state
state = {
users: [],
//是否为第一次打开
isFirst: true,
//是否处于加载中
isLoading: false,
err: false,
}
- 订阅信息
只要发布sendMsg,就执行函数
componentDidMount() {
this.token = PubSub.subscribe("sendMsg", (_, stateobj) => {
this.setState(stateobj)
})
}
- 取消订阅
//组件被卸载
componentWillUnmount() {
PubSub.unsubscribe(this.token)
}
三、fetch发送请求(关注分离设计思想)
fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求
try {
//关注分离
const response = await fetch(`/api/search/users?q=${value}`)
const data = await response.json()
PubSub.publish("sendMsg", { isLoading: false, users: data.items })
} catch (error) {
console.log("请求出错")
PubSub.publish("sendMsg", { isLoading: false, err: error.message })
}