React 学习笔记(21)React axios&消息订阅GitHub用户搜索接口项目

607 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

前言

前面一篇文章学习了axios的基本使用和代理配置,今天学习一下axios在真实的项目中的利用,同时还要了解一个重要的功能,使用订阅机制实现组件间信息通信,之前都是使用props传递数据。

消息订阅(subscribe)-发布(publish)机制

最主要目的是解决多层组件之间通信在一层一层的传递数据的问题, 可以在直接在触发事件的组件中发布消息 监听组件中订阅消息即可。

需要注意的是页面在销毁时要销毁订阅,否则可能会造成内存溢出。需要引入pubsub-js库,在今天的案例中仅仅是使用到兄弟组件之间的数据传递'

需要使用npm install pubsub-js在脚手架中安装这个库才能使用

使用API

GitHub使用的开发用户搜索接口:

https://api.github.com/search/users?q={关键字}

自己用自己的用户名实际测试了一下,应该是有限流,单个IP过多请求就会被Ban: image.png

项目验证

还是做一个列表筛选渲染项目,功能大概是列表关键字筛选,数据的请求渲染图片展示。
主要是拆分两个子组件List,Search,项目目录为:

image.png 从setupProxy.js,修改代理重定向到GitHub接口

const {createProxyMiddleware } = require('http-proxy-middleware');
   module.exports = function(app) {
     app.use(
        createProxyMiddleware('/api1', {  //需要转发的请求前缀,这个自己自定义(所有带有/dev前缀的请求都会转发给8080)
         target: 'http://api.github.com/', //配置转发目标地址(能返回数据的服务器地址)
         changeOrigin: true, //控制服务器接收到的请求头中host字段的值
         pathRewrite: {'^/api1': ''} //去掉这个自定义缀,保证交给后台服务器的是正常请求地址(必须配置)
       })
     )
   }

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:[], //初始化空的用户数组列表
		isFirst:true, //第一次打开,现实帮助信息
		isLoading:false, //接口请求中提示
		err:'',  //展示接口错误信息
	} 

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

	render() {
		return (
			<div className="container">
				<Search updateAppState={this.updateAppState}/>
				<List {...this.state}/>
			</div>
		)
	}
}
  • 父组件定义了四个状态,使用...展开运算符给自主键List传递了state对象
  • 定义了一个search 组件传递过来的updateAppState的回调函数

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更新状态
		PubSub.publish('show_status',{isFirst:false,isLoading:true})
		//发送网络请求
		axios.get(`/api1/search/users?q=${keyWord}`).then(
			response => {
				//请求成功后通知List更新状态
				PubSub.publish('show_status',{isLoading:false,users:response.data.items})
			},
			error => {
				//请求失败后通知App更新状态
				PubSub.publish('show_status',{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>
		)
	}
}

  • 引入了pubsub-js库,请求前发,接收到数据,或者请求错误3种状态下都向列表组件发送订阅消息,告诉列表的现实状态,并传递了相关数据,非常简单。
  • 按键点击回调函数search
  • 使用回调函数的形式绑定refs,通过refs获取到了用户的输入的数据传到axios请求用户数据。

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('show_status', (_, 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>
		)
	}
}

  • 初始化组件state四个状态,和父组件一样,然后在这个自主键挂载完毕的生命周期钩子函数componentDidMount种又从消息订阅中获取到这几个state的值,给这个几个state赋值。这几个state是其兄弟组件Search中获取到的。
  • componentWillUnmount ,在组件卸载前销毁了这个消息发布订阅。

index.css:

.album {
  min-height: 50rem; 
  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%;
}

.card > img :>为子选择器,对孙选择器不起作用,如果没有小于符号就是对孙子选择器起作用

效果&总结:

33.gif 这个列表展示用户的头像,和用户名,并使用a标签包裹,进行了GitHub主页的跳转。

今天学习到了消息订阅发布的方式进行组件间数据的传递,的确非常简单方便,消息订阅的时候使用了箭头函数的返回定义了一个页面的token用来销毁。这里不仅仅适用于兄弟组件之间的数据沟通,还适用于任何组件之间的的沟通。