React ajax

51 阅读3分钟

React ajax

目录

[TOC]

目录

[TOC]

前置说明

  1. React本身只关注于界面,并不包含发送ajax请求的代码
  2. 前端应用需要通过ajax请求与后台进行交互(json数据)
  3. react应用中需要集成第三方ajax(或自己封装)

. 常用的ajax请求库

  1. jQuery:比较重,如果需要另外引入不建议使用
  2. axios:轻量级,建议使用
    1. 封装XmlHttpRequest对象的ajax
    2. promise风格
    3. 可以用在浏览器端和node服务器端

axios

GitHub - axios/axios: Promise based HTTP client for the browser and node.js

相关API
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response.data);
  })
  .catch(function (error) {
    console.log(error);
  });
 
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
export default class App extends Component {
 
	getStudentData = () => {
		axios.get('http://localhost:3000/api1/students').then(
			response => { console.log('成功了', response.data); },
			error => { console.log('失败了', error); }
		)
	}
 
	getCarData = () => {
		axios.get('http://localhost:3000/api2/cars').then(
			response => { console.log('成功了', response.data); },
			error => { console.log('失败了', error); }
		)
	}
 
	render() {
		return (
			<div>
				<button onClick={this.getStudentData}>点我获取学生数据</button>
				<button onClick={this.getCarData}>点我获取汽车数据</button>
			</div>
		)
	}
}

使用代理服务器解决跨域问题 :客户端请求代理服务器 代理服务器跟客户端处于同源下,由代理服务器转发给服务器(代理服务器跟服务器没有跨域问题)

代理服务器有指定的路由就不在转发给服务器(/index)

配置代理 方法一

在package.json中追加如下配置 :"proxy":"http://localhost:5000"

    1. 优点:配置简单,前端请求资源时可以不加任何前缀。
    1. 缺点:不能配置多个代理。
    1. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)
配置代理  方法二

第一步:创建代理配置文件  在src下创建配置文件:src/setupProxy.js

编写setupProxy.js配置具体代理规则:

 const proxy = require('http-proxy-middleware')
   
   module.exports = function(app) {
     app.use(
       proxy('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
         target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
         changeOrigin: true, //控制服务器接收到的请求头中host字段的值
         /*
         	changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
         	changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
         	changeOrigin默认值为false,但我们一般将changeOrigin值设为true,欺骗服务器
         */
         pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
       }),
       proxy('/api2', { 
         target: 'http://localhost:5001',
         changeOrigin: true,
         pathRewrite: {'^/api2': ''}
       })
     )
   }
    1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
    1. 缺点:配置繁琐,前端请求资源时必须加前缀。

案例—github用户搜索

请求地址: api.github.com/search/user…

设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办

ES6小知识点 解构赋值+重命名
let obj = { a: { b: { c: 1 } } }
const { a: { b: { c: data } } } = obj
console.log(data);
消息订阅与发布机制
  1. 工具库: PubSubJS
  2. 下载: npm install pubsub-js --save
  3. 使用:
    1. import PubSub from 'pubsub-js' //引入
    2. PubSub.subscribe('delete', function(data){ }); //订阅
    3. PubSub.publish('delete', data) //发布消息

  • 1.先订阅(接收方),再发布 (发送方)(理解:有一种隔空对话的感觉)
  • 2.适用于任意组件间通信
  • 3.要在组件的componentWillUnmount中取消订阅
fetch发送请求(关注分离的设计思想)
  1. fetch documentation
  2. fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求
  3. 老版本浏览器可能不支持
  4. 传统 Ajax 已死,Fetch 永生 - SegmentFault 思否
 try {
    const response= await fetch(`/api1/search/users2?q=${keyWord}`)
    const data = await response.json()
    console.log(data);
    } catch (error) {
        console.log('请求出错',error);
    }

相关API

//1)GET请求
fetch(url).then(function(response) {
    return response.json()
  }).then(function(data) {
    console.log(data)
  }).catch(function(e) {
    console.log(e)
  });
//2)POST请求
 fetch(url, {
    method: "POST",
    body: JSON.stringify(data),
  }).then(function(data) {
    console.log(data)
  }).catch(function(e) {
    console.log(e)
  })
list组件
  • 三元运算符连问  isFirst ?

    欢迎使用,输入关键字,最后点击搜索

    : isLoding ?

    Loadding.......

    :err ? <h2 style={{ color: 'red' }}>{err} :users.map((userObj)={}
  • componentDidMount初始化钩子 componentWillUnmount即将卸载钩子
  • import PubSub from 'pubsub-js' 发布订阅第三方库
  • 接收数据订阅信息  PubSub.subscribe 记得取消订阅 PubSub.unsubscribe
import React, { Component } from 'react'
import PubSub from 'pubsub-js'
import './index.css'
export default class List extends Component {
	render() {
		const { users, isFirst, isLoding, err } = this.state
		return (
			<div className="row">
				{
					isFirst ? <h2>欢迎使用,输入关键字,最后点击搜索</h2> :
						isLoding ? <h2>Loadding.......</h2> :
							err ? <h2 style={{ color: 'red' }}>{err} </h2> :
								users.map((userObj) => {
									return (
										<div className="card" key={userObj.id}>
											<a href={userObj.html_url} target="_blank" rel="noreferrer">
												<img alt='head_portait' src={userObj.avatar_url} style={{ width: '100px' }} />
											</a>
 
											<p className="card-text">{userObj.login}</p>
										</div>
									)
								})
				}
 
 
			</div>
		)
	}
	state = {
		users: [],//初始值为数组
		isFirst: true,//是否为第一次打开
		isLoding: false,//标识是否处于加载中
		err: ''//存储请求相关错误信息
	}
	//初始化状态订阅消息
	componentDidMount() {
		this.token = PubSub.subscribe('sub', (_, data) => {
			this.setState(data)
		})
	}
	//即将卸载
	componentWillUnmount() {
		//取消订阅·
		PubSub.unsubscribe(this.token)
	}
}
search组件
  • PubSub.publish 发布消息 发送数据方
  • promise.then 返回的值为非promise实例,这个promise为成功值为undefined
  • 返回一个初始化状态的promise中断 可以防止穿透
  • await 右边必须为promise实例,必须使用async修饰  使用try,catch捕获
  • fetch发送请求(关注分离的设计思想)
import React, { Component } from 'react'
import PubSub from 'pubsub-js'
import axios from 'axios'
 
export default class Search extends Component {
	render() {
		return (
			<section className="jumbotron">
				<h3 className="jumbotron-heading">Search Github User</h3>
				<div>
					<input ref={c => this.keyWordElement = c} type="text" placeholder="输入关键字点击搜索" />&nbsp;
					<button onClick={this.search}>搜索</button>
				</div>
			</section>
		)
	}
	// PubSub.publish 发布消息
	search = async () => {
		//获取用户的输入(连续解构赋值并重命名)
		const { keyWordElement: { value: keyWord } } = this
		// 发送请求前通知list更新状态
		PubSub.publish('sub', { isFirst: false, isLoding: true })
		// #region 发送网络请求-----------使用axios发请求
		/* 	axios.get(`http://localhost:3000/api1/search/users?q=${keyWord}`)
				.then(response => {
					// 请求成功后通知list更新状态
					PubSub.publish('sub', { isLoding: false, users: response.data.items })
				},
					error => { PubSub.publish('sub', { isLoding: false, err: error.message }) }
				) */
		// #endregion
 
		//发送网络请求----使用fetch(未优化版)
		// fetch(`/api1/search/users?q=${keyWord}`).then(
		// 	response => {
		// 		console.log('联系服务器成功了');
		// 		return response.json()
		// 	},
		// 	///返回的值为非promise实例,这个promise为成功值为undefined
		// 	err => {
		// 		console.log('联系服务器失败了', err);
		// 		//返回一个初始化状态的promise中断
		// 		return new Promise(() => { })
		// 	}
		// ).then(
		// 	response => {
		// 		console.log('获取数据成功了', response);
 
		// 	},
		// 	err => { console.log('获取数据失败了', err); }
		// )
		// 使用try,catch捕获
		try {
			const response = await fetch(`/api1/search/users?q=${keyWord}`)
			//await 右边必须为promise实例,必须使用async修饰
			const data = await response.json()
			PubSub.publish('sub', { isLoding: false, users: data.items })
			console.log(data);
		} catch (error) {
			console.log('请求出错了', error);
			PubSub.publish('sub', { isLoding: false, err: error.message })
		}
 
	}
}