本篇通过消息订阅与发布实现任意组件间通信,来完成github搜索案例。
消息订阅与发布的基本使用
npm install --save pubsub-js
,安装第三方库pubsub-js。import PubSub from "pubsub-js"
,引入第三方库PubSub。- 订阅消息:
id = PubSub.subscribe(消息名,callback)
,且callback的第一个形参默认是消息名,后面则是开发者自己传入的参数。 - 发布消息:
PubSub.publish(消息名,开发者的参数)
。 - 取消订阅:
PubSub.unsubscribe(id)
。
代码变更涉及以下文件:
- App.js,即App组件。
- components/Search/index.jsx,即Search组件。
- components/List/index.jsx,即List组件。
App.js(App组件)
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>
)
}
}
Search/index.jsx(Search组件)
import React, { Component } from 'react';
import PubSub from 'pubsub-js';
import axios from "axios";
export default class index extends Component {
handleClick = () => {
const {keywordEle:{value:keyword}} = this;
PubSub.publish("changeState",{isFirst:false,isLoading:true});
axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
response => {
console.log("请求成功了",response.data);
PubSub.publish("changeState",{isLoading:false,users:response.data.items});
},
error => {
PubSub.publish("changeState",{isLoading:false,errorMsg:error.message});
}
)
}
render() {
const {handleClick} = this;
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">搜索Github用户</h3>
<div>
<input ref={c => this.keywordEle = c} type="text" placeholder="输入关键词"/>
<button onClick={handleClick}>搜索</button>
</div>
</section>
)
}
}
List/index.jsx(List组件)
import React, { Component } from 'react';
import PubSub from 'pubsub-js';
import "./index.css";
export default class index extends Component {
state = {
users:[],
isFirst:true,
isLoading:false,
errorMsg:""
}
changeState = (msgName,stateObj) => {
this.setState(stateObj);
}
componentDidMount(){
this.pubId= PubSub.subscribe("changeState",this.changeState)
}
componentWillUnmount(){
PubSub.unsubscribe(this.pubId);
}
render() {
const { isFirst,isLoading,users,errorMsg } = this.state;
return (
<div className="row">
{ isFirst ? <h2>欢迎使用,输入关键词,点击按钮即可搜索</h2> :
isLoading ? <h2>正在加载...</h2> :
errorMsg ? <h2 style={{color:'red'}}>{errorMsg}</h2> :
users.map(userObj => {
return (
<div className="card" key={userObj.id}>
<a href={userObj.html_url} target="_blank" rel="noreferrer">
<img alt="avatar" src={userObj.avatar_url} style={{ width: '100px' }} />
</a>
<p className="card-text">{userObj.login}</p>
</div>
)
})
}
</div>
)
}
}