基本功能
在搜索框中输入搜索,然后不通过父子传值的方式改为兄弟组件之间传值实现搜索结果的展示。点击搜索后,得到结果之后通知List组件进行界面数据更新
关键代码
1、安装pubsub-js
npm add pubsub-js
2、App.js
import React, { Component } from 'react';
import Search from './components/Search';
import List from './components/List';
class App extends Component {
render() {
return (
<div className="container">
<Search />
<List/>
</div>
);
}
}
export default App;
3、List=>index.js 在componentDidMount中订阅notice通知,记得在页面销毁的时候取消订阅
import React, { Component } from 'react';
import PubSub from 'pubsub-js'
import './index.css'
class List extends Component {
state={//初始化状态
users:[], //users初始值为数组
isFirst:true,//是否为第一次打开页面
isLoading:false,//是否处于加载中
err:''//存储请求相关的错误信息
}
componentDidMount(){
this.token=PubSub.subscribe('notice',(_,stateObj)=>{
this.setState(stateObj)
})
}
componentWillUnmount(){
PubSub.unsubscribe();
}
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 className="card" key={userObj.id}>
<a href={userObj.html_url} target="_blank" rel="noreferrer" >
<img src={userObj.avatar_url} style={{width:'100px'}} alt='head_portrait'/>
</a>
<p className="card-text">{userObj.login}</p>
</div>
)
})
}
</div>
);
}
}
export default List;
4、Search=>index.js 在搜索后需要通知到List组件进行更新
import React, { Component } from 'react';
import PubSub from 'pubsub-js'
import axios from 'axios';
class Search extends Component {
search=()=>{
//获取用户的输入(连续解构赋值+重命名)
const{keyWordElement:{value:keyWord}}=this;
console.log(keyWord)
//发送网络请求前通知List更新状态
PubSub.publish('notice',{isFirst:false,isLoading:true})
//发送网络请求
axios.get(`/api1/search/users?q=${keyWord}`).then(response=>{
PubSub.publish('notice',{isLoading:false,users:response.data.items})
},error=>{
//请求失败后通知app更新状态
PubSub.publish('notice',{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>
);
}
}
export default Search;
5、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%;
}
代理setProxy.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':''}//重写请求路径
})
)
}