React ajax请求 及axios、pubsub、fetch使用

文章目录

  • React ajax
    • 前置说明
    • 常用ajax请求库
  • axios
  • 消息订阅-发布机制
  • Fetch
  • 案例——github用户搜索

React ajax

前置说明

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

常用ajax请求库

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

axios

axios:是对ajax进行了封装,可以实现异步请求
1、前后端分离:在前端中引入axios.js文件
2、模块开发:在项目中安装axios模块

axios中常用的方法:

  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])

GET请求:

  • 方式一:

    axios({
           
    		method: 'get',  // 默认请求方式为get
    		url: 'api',
    		params: {
             // 传递参数
    			key: value
    		},
    		headers: {
             // 设置请求头信息
    			key: value
    		}
    		responseType: 'json'
    	}).then(response => {
            // 请求成功
    		let res = response.data;
    		console.log(res);
    	}).catch(error => {
             // 请求失败,
    		console.log(error);
    });
    
  • 方式二:

    axios.get("api", {
           
    		params: {
              // 传递参数
    			key: value
    		},
    		headers: {
             // 设置请求头信息,可以传递空值
    			key: value
    		}
    	}).then(response => {
           
    		let res = response.data; // 请求成功
    		console.log(res);
    	}).catch(error => {
             // 请求失败,
    		console.log(error);
    });
    

POST请求

  • 方式一:

    // 注:post请求方法有的要求参数格式为formdata格式,此时需要借助 Qs.stringify()方法将对象转换为字符串
    let obj = qs.stringify({
           
    	key: value
    });
    axios({
           
    	method: 'post',
    	url: 'api',
    	data: obj, // 传递参数
    	headers: {
             // 设置请求头信息
    		key: value
    	}
    	responseType: 'json'
    }).then(response => {
            // 请求成功
    	let res = response.data;
    	console.log(res);
    }).catch(error => {
            // 请求失败,
    	console.log(error);
    });
    
  • 方式二:

    let data = {
           key: value},
    let headers = {
           
    				USERID: "",
    				TOKEN: ""
    			};
    // 若无headers信息时,可传空对象占用参数位置
    axios.post("api", qs.stringify(data), {
           
    		headers
    }).then(response => {
           // 请求成功
    	let res = response.data;
    	console.log(res);
    }).catch(error => {
            // 请求失败
    	console.log(error);
    });
    

Qs的使用:

  • 引用cdn或者使用npm、cnpm或者yarn进行插件安装

  • 使用cdn时,默认全局变量为Qs

  • Qs基本方法使用:

    • qs.stringify() 方法:将目标数据转换为 string字符串
    • qs.parse() 方法:将对象字符串格式的数据转换为 对象格式

消息订阅-发布机制

  1. 工具库: PubSubJS

  2. 下载: npm install pubsub-js --save

  3. 使用:

    import PubSub from 'pubsub-js' //引入
    	
    PubSub.subscribe('delete', function(data){
            }); //订阅
    
    PubSub.publish('delete', data) //发布消息
    

Fetch

  • fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求

  • 老版本浏览器可能不支持

  • 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)
    })
    

案例——github用户搜索

React ajax请求 及axios、pubsub、fetch使用_第1张图片

目录格式:
React ajax请求 及axios、pubsub、fetch使用_第2张图片
代码文件:

1、使用axios方法:

index.html:

DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <link rel="stylesheet" href="./css/bootstrap.css">
    <title>React Apptitle>
  head>
  <body>
    <div id="root">div>
  body>
html>

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

App.js:

import React, {
      Component } from 'react'
import Search from './components/Search'
import List from './components/List'

export default class App extends Component {
     

    state = {
      //初始化状态
        users:[], //users初始值为数组
        isFirst:true, //是否为第一次打开页面
        isLoading:false,//标识是否处于加载中
        err:'',//存储请求相关的错误信息
    }

    //更新App的state
    updateAppState = (stateObj)=>{
     
        this.setState(stateObj)
    }

    render() {
     
        return (
            <div className="container">
                <Search updateAppState={
     this.updateAppState}/>
                <List {
     ...this.state}/>
            </div>
        )
    }
}

setupProxy.js(配置代理):

const proxy = require('http-proxy-middleware')

module.exports = function(app){
     
	app.use(
		proxy('/api1',{
      //遇见/api1前缀的请求,就会触发该代理配置
			target:'http://localhost:5000', //请求转发给谁
			changeOrigin:true,//控制服务器收到的请求头中Host的值
			pathRewrite:{
     '^/api1':''} //重写请求路径(必须)
		})
	)
}

List目录下的index.css:

.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: .75rem;
    margin-bottom: 2rem;
    border: 1px solid #efefef;
    text-align: center;
}

.card > img {
     
    margin-bottom: .75rem;
    border-radius: 100px;
}

.card-text {
     
    font-size: 85%;
}

List目录下的index.jsx:

import React,{
     Component} from "react";
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>Loading......</h2> :
                            err ? <h2 style={
     {
     color:'red'}}>{
     err}</h2> :
                                users.map((userObj)=>{
     
                                    return (
                                        <div key={
     userObj.id} className="card">
                                            <a rel="noreferrer" href={
     userObj.html_url} target="_blank">
                                                <img alt="head_portrait" src={
     userObj.avatar_url} style={
     {
     width:'100px'}}/>
                                            </a>
                                            <p className="card-text">{
     userObj.login}</p>
                                        </div>
                                    )
                                })
                }
            </div>
        )
    }
}

Search目录下的index.jsx:

import React,{
     Component} from "react";
import axios from 'axios';

export default class Search extends Component{
     
    search=()=>{
     
        //获取用户的输入  连续解构赋值+重命名
        const {
     keyWordElement:{
     value:keyWord}}=this;
        //发送请求前通知App更新状态
        this.props.updateAppState({
     isFirst: false,isLoading: true})
        //发送网络请求
        axios.get(`/api1/search/users?q=${
       keyWord}`).then(
            response=>{
     
                this.props.updateAppState({
     isLoading: false,users: response.data.items})
            },
            error=>{
     
                this.props.updateAppState({
     isLoading: false,err:error.message})
            }
        )
    }
    render() {
     
        return(
            <section className="jumbotron">
                <h3 className="jumbotron-heading">搜索github用户</h3>
                <div>
                    <input ref={
     c => this.keyWordElement = c} type="text" placeholder="输入关键词点击搜索"/>&nbsp;
                    <button onClick={
     this.search}>搜索</button>
                </div>
             </section>
        )
    }
}

服务器 server.js: 需要先启动服务器

const express = require("express")
const axios = require("axios")
const app = express()


/*
  请求地址: http://localhost:3000/search/users?q=aa

  后台路由
    key: /search/users
    value: function () {}
*/
app.get("/search/users", function (req, res) {
     
  const {
     q} = req.query
  axios({
     
    url: 'https://api.github.com/search/users',
    params: {
     q}
  }).then(response => {
     
    res.json(response.data)
  })
})

app.listen(5000, "localhost", (err) => {
     
  if (!err){
     
  	console.log("服务器启动成功")
  	console.log("请求github真实数据请访问:http://localhost:5000/search/users")
  } 
  else console.log(err);
})

2、使用pubsub方法:

其余文件代码均不变

App.js:

import React, {
      Component } from 'react'
import Search from './components/Search'
import List from './components/List'

export default class App extends Component {
     
    render() {
     
        return (
            <div className="container">
                <Search/>
                <List/>
            </div>
        )
    }
}

List目录下的index.jsx:

import React,{
     Component} from "react";
import PubSub from 'pubsub-js';
import './index.css'

export default class List extends Component{
     
    state = {
      //初始化状态
        users:[], //users初始值为数组
        isFirst:true, //是否为第一次打开页面
        isLoading:false,//标识是否处于加载中
        err:'',//存储请求相关的错误信息
    }
    componentDidMount() {
     
        this.token=PubSub.subscribe('msg',(_,stateObj)=>{
     
            this.setState(stateObj);
        })
    }
    componentWillUnmount() {
     
        PubSub.unsubscribe(this.token);
    }

    render() {
     
        const {
     users,isFirst,isLoading,err} = this.state
        return (
            <div className="row">
                {
     
                    isFirst ? <h2>欢迎使用,输入关键字,随后点击搜索</h2> :
                        isLoading ? <h2>Loading......</h2> :
                            err ? <h2 style={
     {
     color:'red'}}>{
     err}</h2> :
                                users.map((userObj)=>{
     
                                    return (
                                        <div key={
     userObj.id} className="card">
                                            <a rel="noreferrer" href={
     userObj.html_url} target="_blank">
                                                <img alt="head_portrait" src={
     userObj.avatar_url} style={
     {
     width:'100px'}}/>
                                            </a>
                                            <p className="card-text">{
     userObj.login}</p>
                                        </div>
                                    )
                                })
                }
            </div>
        )
    }
}

Search目录下的index.jsx:

import React,{
     Component} from "react";
import PubSub from 'pubsub-js';
import axios from 'axios';

export default class Search extends Component{
     
    search=()=>{
     
        //获取用户的输入  连续解构赋值+重命名
        const {
     keyWordElement:{
     value:keyWord}}=this;
        //发送请求前通知List更新状态
        // this.props.updateAppState({isFirst: false,isLoading: true})
        PubSub.publish('msg',{
     isFirst: false,isLoading: true})
        //发送网络请求
        axios.get(`/api1/search/users?q=${
       keyWord}`).then(
            response=>{
     
                // this.props.updateAppState({isLoading: false,users: response.data.items})
                PubSub.publish('msg',{
     isLoading: false,users: response.data.items})
            },
            error=>{
     
                // this.props.updateAppState({isLoading: false,err:error.message})
                PubSub.publish('msg',{
     isLoading: false,err:error.message})
            }
        )

    }
    render() {
     
        return(
            <section className="jumbotron">
                <h3 className="jumbotron-heading">搜索github用户</h3>
                <div>
                    <input ref={
     c => this.keyWordElement = c} type="text" placeholder="输入关键词点击搜索"/>&nbsp;
                    <button onClick={
     this.search}>搜索</button>
                </div>
             </section>
        )
    }
}

3、使用fetch方法:

App.js:

import React, {
      Component } from 'react'
import Search from './components/Search'
import List from './components/List'

export default class App extends Component {
     
    render() {
     
        return (
            <div className="container">
                <Search/>
                <List/>
            </div>
        )
    }
}

List目录下的index.jsx:

import React,{
     Component} from "react";
import PubSub from 'pubsub-js';
import './index.css'

export default class List extends Component{
     
    state = {
      //初始化状态
        users:[], //users初始值为数组
        isFirst:true, //是否为第一次打开页面
        isLoading:false,//标识是否处于加载中
        err:'',//存储请求相关的错误信息
    }
    componentDidMount() {
     
        this.token=PubSub.subscribe('msg',(_,stateObj)=>{
     
            this.setState(stateObj);
        })
    }
    componentWillUnmount() {
     
        PubSub.unsubscribe(this.token);
    }

    render() {
     
        const {
     users,isFirst,isLoading,err} = this.state
        return (
            <div className="row">
                {
     
                    isFirst ? <h2>欢迎使用,输入关键字,随后点击搜索</h2> :
                        isLoading ? <h2>Loading......</h2> :
                            err ? <h2 style={
     {
     color:'red'}}>{
     err}</h2> :
                                users.map((userObj)=>{
     
                                    return (
                                        <div key={
     userObj.id} className="card">
                                            <a rel="noreferrer" href={
     userObj.html_url} target="_blank">
                                                <img alt="head_portrait" src={
     userObj.avatar_url} style={
     {
     width:'100px'}}/>
                                            </a>
                                            <p className="card-text">{
     userObj.login}</p>
                                        </div>
                                    )
                                })
                }
            </div>
        )
    }
}

Search目录下的index.js:

import React,{
     Component} from "react";
import PubSub from 'pubsub-js';
// import axios from 'axios';

export default class Search extends Component{
     
    search=async ()=> {
     
        //获取用户的输入  连续解构赋值+重命名
        const {
     keyWordElement: {
     value: keyWord}} = this;
        //发送请求前通知List更新状态
        // this.props.updateAppState({isFirst: false,isLoading: true})
        PubSub.publish('msg', {
     isFirst: false, isLoading: true})

        //发送网络请求
        // axios.get(`/api1/search/users?q=${keyWord}`).then(
        //     response=>{
     
        //         // this.props.updateAppState({isLoading: false,users: response.data.items})
        //         PubSub.publish('msg',{isLoading: false,users: response.data.items})
        //     },
        //     error=>{
     
        //         // this.props.updateAppState({isLoading: false,err:error.message})
        //         PubSub.publish('msg',{isLoading: false,err:error.message})
        //     }
        // )
        try{
     
            const response = await fetch(`/api1/search/users?q=${
       keyWord}`)
            const data = await response.json()
            PubSub.publish('msg', {
     isFirst: false, users:data.items})
        }catch (error){
     
            PubSub.publish('msg', {
     isLoading: false,err:error.message})
        }

    }
    render() {
     
        return(
            <section className="jumbotron">
                <h3 className="jumbotron-heading">搜索github用户</h3>
                <div>
                    <input ref={
     c => this.keyWordElement = c} type="text" placeholder="输入关键词点击搜索"/>&nbsp;
                    <button onClick={
     this.search}>搜索</button>
                </div>
             </section>
        )
    }
}

案例相关知识点:

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

  2. ES6小知识点:解构赋值+重命名

    let obj = {
           a:{
           b:1}}
    const {
           a} = obj; //传统解构赋值
    const {
           a:{
           b}} = obj; //连续解构赋值
    const {
           a:{
           b:value}} = obj; //连续解构赋值+重命名
    
  3. 消息订阅与发布机制(pubsub)

    1. 先订阅,再发布(理解:有一种隔空对话的感觉)
    2. 适用于任意组件间通信
    3. 要在组件的componentWillUnmount中取消订阅
  4. fetch发送请求(关注分离的设计思想)

    try {
           
        const response= await fetch(`/api1/search/users2?q=${
             keyWord}`)
        const data = await response.json()
        console.log(data);
    } catch (error) {
           
       console.log('请求出错',error);
    }
    

你可能感兴趣的:(React,react.js,ajax,axios,消息订阅,fetch)