目录
前言
React兄弟组件之间依靠父组件通信,需要在父组件提前准备好一个函数,并且所有的state状态都要写到父组件里面,想要更新状态,就得利用该函数和props一层一层的传递。而使用PubSubJs消息订阅与发布,就可以实现React兄弟组件之间直接通信。另外本案例还涉及到了同源策略导致的跨域问题,我们会用配置代理的方式实现跨域请求。
一、准备工作
开始案例之前我们需要先准备好一个5000端口的服务器,接口为https://api.github.com/users
const express = require("express");
const axios = require("axios");
const app = express();
app.get("/search/users", function (req, res) {
const { q } = req.query;
axios({
url: "https://api.github.com/users",
params: { q },
}).then((response) => {
res.json(response.data);
});
});
app.listen(5000, "localhost", (err) => {
if (!err) {
console.log("服务器启动成功");
console.log("请求github真实数据请访问:http://localhost:5000/search/users");
} else console.log(err);
});
npm install pubsub-js --save
引入PubSubJs到需要消息订阅的组件中
import PubSub from 'pubsub-js'
二、拆分组件
1.配置代理
// 引入代理
const proxy = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
proxy.createProxyMiddleware("/api1", {
//api1是需要转发的请求(所有带有 /api1 前缀的请求都会转发给5000)
target: "http://localhost:5000", // 配置请求转发的目标地址(能返回数据的服务器地址)
changeOrigin: true, //控制服务器接收到的请求头中host字段的值
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
changeOrigin默认值为false,但我们一般将changeOrigin值设为true
*/
pathRewrite: { "^/api1": "" }, // 去除请求前缀,保证交给服务器的是正常请求的地址(必须配置)
}),
2.App父组件
// 引入react核心库
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>
)
}
}
3.Search子组件
import React, { Component } from 'react'
import PubSub from 'pubsub-js'
import axios from 'axios'
export default class Search extends Component {
//点击搜索回调
updateUserData = () => {
// 获取输入的值,(连续解构+重命名)的方式
const { getKeycode: { value: keyWord } } = this
console.log(keyWord);
// 首次访问,通知List更新状态
PubSub.publish('User_Data', { isFirst: false, isLoading: true })
// 发送请求
axios.get(`/api1/search/users?q=${keyWord}`).then(
// 请求成功,通知List组件更新状态
response => {
PubSub.publish('User_Data', { isLoading: false, userData: response.data })
},
// 请求失败了,通知List更新状态
error => {
PubSub.publish('User_Data', { isLoading: false, error: error.message })
}
)
}
render() {
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">Search Github Users</h3>
<div>
<input ref={c => { this.getKeycode = c }} type="text" placeholder="enter the name you search" />
<button onClick={this.updateUserData} >Search</button>
</div>
</section>
)
}
}
4.List子组件
import React, { Component } from 'react'
import PubSub from 'pubsub-js'
import './index.css'
export default class List extends Component {
state = {
userData: [], //初始化状态为数组
isFirst: true, //是否第一次访问
isLoading: false, //是否正在加载
error: '' //返回错误
}
// List组件挂载时订阅
componentDidMount() {
// 订阅消息,接收改变的状态值
this.token = PubSub.subscribe('User_Data', (_, data) => {
this.setState(data)
})
}
// List组件卸载时取消订阅
componentWillUnmount() {
PubSub.unsubscribe(this.token)
}
render() {
// 获取状态
const { userData, isFirst, isLoading, error } = this.state
return (
<div className="row">
{
/*判断是否是第一次访问 */
isFirst ? <h2>欢迎您来访!!!</h2> :
/* 判断是否正在加载中 */
isLoading ? <h2>加载中。。。。。。。</h2> :
/* 判断请求是否出错 */
error ? <h2>出错了!?!?!?</h2> :
/* 将请求到的数据渲染到页面 */
userData.map(userObj => {
return (
<div className="card" key={userObj.id}>
<a href={userObj.html_url} rel="noreferrer">
<img alt='head-t' src={userObj.avatar_url} style={{ width: '100px' }} />
</a>
<p className="card-text">{userObj.login}</p>
</div>
)
})
}
</div>
)
}
}