06_React ajax(github搜索案例props版、订阅与发布版)

一、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()

  1. "/api1":含有"/api1"前缀的请求
  2. target:  请求转发给谁
  3. changeOrigin :控制服务器收到的响应头 Host 字段的值
    1. 设置为true时,服务器收到的请求头中的host为:localhost:5000
    2. 设置为false时,服务器收到的请求头中的host为:localhost:3000
    3. 默认值为false,一般将changeOrigin值设为true
  4. 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"
          />
          &nbsp;<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"
          />
          &nbsp;<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 })
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

才不吃胡萝卜嘞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值