持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情
前言
前面一篇文章学习了axios的基本使用和代理配置,今天学习一下axios在真实的项目中的利用,同时还要了解一个重要的功能,使用订阅机制实现组件间信息通信,之前都是使用props传递数据。
消息订阅(subscribe)-发布(publish)机制
最主要目的是解决多层组件之间通信在一层一层的传递数据的问题, 可以在直接在触发事件的组件中发布消息 监听组件中订阅消息即可。
需要注意的是页面在销毁时要销毁订阅,否则可能会造成内存溢出。需要引入pubsub-js库,在今天的案例中仅仅是使用到兄弟组件之间的数据传递'
需要使用npm install pubsub-js在脚手架中安装这个库才能使用
使用API
GitHub使用的开发用户搜索接口:
https://api.github.com/search/users?q={关键字}
自己用自己的用户名实际测试了一下,应该是有限流,单个IP过多请求就会被Ban:
项目验证
还是做一个列表筛选渲染项目,功能大概是列表关键字筛选,数据的请求渲染图片展示。
主要是拆分两个子组件List,Search,项目目录为:
从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="输入关键词点击搜索"/>
<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 :>为子选择器,对孙选择器不起作用,如果没有小于符号就是对孙子选择器起作用
效果&总结:
这个列表展示用户的头像,和用户名,并使用a标签包裹,进行了GitHub主页的跳转。
今天学习到了消息订阅发布的方式进行组件间数据的传递,的确非常简单方便,消息订阅的时候使用了箭头函数的返回定义了一个页面的token用来销毁。这里不仅仅适用于兄弟组件之间的数据沟通,还适用于任何组件之间的的沟通。