欢迎来到我的博客
博主是一名大学在读本科生,主要学习方向是前端。
目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
目前正在学习的是 R e a c t 框 架 React框架 React框架,中间夹杂了一些基础知识的回顾⌨️
博客主页codeMak1r.的博客
➕关注点赞收藏本文目录
- 前言
- github搜索案例
- axios + PubSubJS实现——消息订阅与发布
- List组件订阅消息
- Search组件发起请求,发布消息
- fetch + PubSubJS实现——消息订阅与发布
- Search组件(fetch)
- github搜索案例源码
- 总结
本文被专栏【React–从基础到实战】收录
前文回顾:setupProxy配置前端跨域
在本案例中,使用的是create-react-app
搭建的脚手架,外面最大的是总的App组件。
在App组件中可以分为两个子组件——Search以及List。
Search包含搜索功能,在Search组件中发送网络请求,返回的数据由List组件渲染到页面中。
这就表示一定存在Search组件到List组件的通信。也就是兄弟组件之间的通信。
PubSubJS是一个star✨数达到4.2k的一个库。
主要功能就是实现任意组件之间的通信,运用的是消息订阅与发布机制。
消息订阅:PubSub.subscribe('Message', func());
消息发布:
PubSub.publish('Message', data);
需要使用数据的组件A订阅一个消息(消息名为订阅时自定义的)
发起请求的组件B接收到服务器返回的数据后将数据作为消息发布出去,发布时指定发布的消息名,该消息名若被组件A订阅了,则会自动将数据传递给A组件,从而实现组件之间的通信。
下载PubSubJS
npm install pubsub-js
yarn add pubsub-js
----
sudo npm install pubsub-js // MAC
导入PubSubJS
import PubSub from 'pubsub-js'
// or when using CommonJS
const PubSub = require('pubsub-js');
下载与导入axios
npm install axios // 下载
import axios from 'axios' //导入
首先我们要先分清,是谁需要订阅消息?谁需要发布消息?
我们可以用订阅报纸来理解,
我想要读取报纸的消息,我就需要订阅报纸;
也就是——List组件想要读取数据,将数据渲染到页面中,那么List组件需要做的就是订阅消息。
而Search组件发送请求,请求成功后将返回的数据交给List组件,那么Search就应该将返回的数据当作发布的消息,只要Search组件发布消息,订阅了消息的List组件就能够接收到。
// 初始化状态
state = {
users: [],
isFirst: true, // 是否为第一次打开页面
isLoading: false, // 是否在加载中
error: '' // 存储请求相关的错误信息
}
componentDidMount() {
// 组件一挂载时就订阅消息
this.token = PubSub.subscribe('userMessage', (_, stateObj) => {
this.setState(stateObj);
})
}
componentWillUnmount() {
// 组件卸载前取消订阅
PubSub.unsubscribe(this.token)
}
// 发送网络请求
axios.get(`/api1/search/users?q=${keyWord}`)
.then(value => {
// 请求成功后通知List更新状态
const { data: { items: users } } = value
PubSub.publish('userMessage', { isLoading: false, users })
}, reason => {
// 请求失败后通知List更新状态
PubSub.publish('userMessage', { isLoading: false, error: reason.message })
})
发起网络请求,并不一定需要axios,甚至都不一定需要XMLHttpRequest。
JS原生的fetch就很好用。
fetch也可以用来发起网络请求,且fetch并不是基于XMLHttpRequest的。
fetch是基于 Promise的,使用的是关注分离的设计思想。
try {
const response = await fetch(`/api1/search/users?q=${keyWord}`)
const data = await response.json()
PubSub.publish('userMessage', { isLoading: false, users: data.items })
} catch (error) {
console.log('出错啦', error)
PubSub.publish('userMessage', { isLoading: false, error: error.message })
}
App.jsx
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.jsx (axios + PubSub)
import React, { Component } from 'react'
import axios from 'axios'
import PubSub from 'pubsub-js';
export default class Search extends Component {
search = () => {
// 获取用户的输入(连续解构赋值)拿到this.inputRef.value + (重命名)value=>keyWord
const { inputRef: { value: keyWord } } = this
// 发送请求前通知List更新状态
PubSub.publish('userMessage', { isFirst: false, isLoading: true })
// 发送网络请求
axios.get(`/api1/search/users234?q=${keyWord}`)
.then(value => {
// 请求成功后通知List更新状态
const { data: { items: users } } = value
PubSub.publish('userMessage', { isLoading: false, users })
}, reason => {
// 请求失败后通知List更新状态
PubSub.publish('userMessage', { isLoading: false, error: reason.message })
})
}
enterSearch = (event) => {
if (event.key !== 'Enter') return
this.search()
}
render() {
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">Search Github Users</h3>
<div>
<input onKeyUp={this.enterSearch}
ref={currentNode => this.inputRef = currentNode}
type="text" placeholder="enter the name you search"
style={{ width: '180px' }} />
<button onClick={this.search}>Search</button>
</div>
</section>
)
}
}
Search.jsx (fetch + PubSub)
import React, { Component } from 'react'
import PubSub from 'pubsub-js';
export default class Search extends Component {
search = async () => {
// 获取用户的输入(连续解构赋值)拿到this.inputRef.value + (重命名)value=>keyWord
const { inputRef: { value: keyWord } } = this
// 发送请求前通知List更新状态
PubSub.publish('userMessage', { isFirst: false, isLoading: true })
try {
const response = await fetch(`/api1/search/users234?q=${keyWord}`)
const data = await response.json()
PubSub.publish('userMessage', { isLoading: false, users: data.items })
} catch (error) {
console.log('出错啦', error)
PubSub.publish('userMessage', { isLoading: false, error: error.message })
}
}
enterSearch = (event) => {
if (event.key !== 'Enter') return
this.search()
}
render() {
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">Search Github Users</h3>
<div>
<input onKeyUp={this.enterSearch}
ref={currentNode => this.inputRef = currentNode}
type="text" placeholder="enter the name you search"
style={{ width: '180px' }} />
<button onClick={this.search}>Search</button>
</div>
</section>
)
}
}
List.jsx
import React, { Component } from 'react'
import PubSub from 'pubsub-js'
import './index.css'
export default class List extends Component {
state = {
users: [],
isFirst: true, // 是否为第一次打开页面
isLoading: false, // 是否在加载中
error: '' // 存储请求相关的错误信息
}
componentDidMount() {
// 组件一挂载时就订阅消息
this.token = PubSub.subscribe('userMessage', (_, stateObj) => {
this.setState(stateObj);
})
}
componentWillUnmount() {
// 组件卸载前取消订阅
PubSub.unsubscribe(this.token)
}
render() {
const { users, isFirst, isLoading, error } = this.state
return (
<div className="row">
{
isFirst ? <h2>Enter The Name You Search...</h2> :
isLoading ? <h2>Loading...</h2> :
error ? <h2 style={{ color: 'red' }}>{error}</h2> :
users.map((userObj) => {
return (
<div key={userObj.id} className="card">
<a rel="noreferrer" href={userObj.html_url} target="_blank">
<img alt='head_sculpture' src={userObj.avatar_url} style={{ width: '100px' }} />
</a>
<p className="card-text">{userObj.login}</p>
</div>
)
})
}
</div>
)
}
}
设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办。
ES6小知识点:解构赋值 + 重命名
let obj = {a: { b:1 }}
const {a} = obj; // 传统解构赋值
const {a: {b}} = obj // 连续解构赋值
const {a: {b: value}} // 连续解构赋值 + 重命名
消息订阅与发布机制
先订阅再发布;(理解:有一种隔空对话的感觉)
适用于任意组件间的通信;
要在组件的componentWillUnmount中取消订阅;
fetch发送请求(关注分离的设计思想)
try {
const response = await fetch(`/api1/search/users?q=${keyWord}`)
const data = await response.json()
PubSub.publish('userMessage', { isLoading: false, users: data.items })
} catch (error) {
console.log('出错啦', error)
PubSub.publish('userMessage', { isLoading: false, error: error.message })
}
如果觉得博主的文章还不错的话
➕关注博主点赞文章收藏文章
✏️原创不易你的支持将会是我最大的动力
感谢观看