【React】github搜索案例实现兄弟组件通信(axios、PubSub、fetch)

前言

欢迎来到我的博客
博主是一名大学在读本科生,主要学习方向是前端。
目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
目前正在学习的是 R e a c t 框 架 React框架 React,中间夹杂了一些基础知识的回顾⌨️
博客主页codeMak1r.的博客
➕关注点赞收藏

本文目录

  • 前言
  • github搜索案例
  • axios + PubSubJS实现——消息订阅与发布
    • List组件订阅消息
    • Search组件发起请求,发布消息
  • fetch + PubSubJS实现——消息订阅与发布
    • Search组件(fetch)
  • github搜索案例源码
  • 总结

本文被专栏【React–从基础到实战】收录
前文回顾:setupProxy配置前端跨域

坚持创作✏️,一起学习,码出未来‍!
【React】github搜索案例实现兄弟组件通信(axios、PubSub、fetch)_第1张图片

github搜索案例

【React】github搜索案例实现兄弟组件通信(axios、PubSub、fetch)_第2张图片
在本案例中,使用的是create-react-app搭建的脚手架,外面最大的是总的App组件。
在App组件中可以分为两个子组件——Search以及List。
Search包含搜索功能,在Search组件中发送网络请求,返回的数据由List组件渲染到页面中。
这就表示一定存在Search组件到List组件的通信。也就是兄弟组件之间的通信。

【React】github搜索案例实现兄弟组件通信(axios、PubSub、fetch)_第3张图片

axios + PubSubJS实现——消息订阅与发布

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组件就能够接收到。

List组件订阅消息

// 初始化状态
state = {
    users: [],
    isFirst: true,  // 是否为第一次打开页面
    isLoading: false,  // 是否在加载中
    error: ''  // 存储请求相关的错误信息
  }
componentDidMount() {
   // 组件一挂载时就订阅消息
   this.token = PubSub.subscribe('userMessage', (_, stateObj) => {
     this.setState(stateObj);
   })
 }
componentWillUnmount() {
   // 组件卸载前取消订阅
   PubSub.unsubscribe(this.token)
 }

Search组件发起请求,发布消息

// 发送网络请求
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 })
  })

fetch + PubSubJS实现——消息订阅与发布

发起网络请求,并不一定需要axios,甚至都不一定需要XMLHttpRequest。
JS原生的fetch就很好用。
fetch也可以用来发起网络请求,且fetch并不是基于XMLHttpRequest的。
fetch是基于 Promise的,使用的是关注分离的设计思想。

Search组件(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 })
}

github搜索案例源码

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' }} />&nbsp;
          <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' }} />&nbsp;
          <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>
    )
  }
}

总结

  1. 设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办。

  2. ES6小知识点:解构赋值 + 重命名

    let obj = {a: { b:1 }}
    const {a} = obj; // 传统解构赋值
    const {a: {b}} = obj // 连续解构赋值
    const {a: {b: value}} // 连续解构赋值 + 重命名
    
  3. 消息订阅与发布机制

    先订阅再发布;(理解:有一种隔空对话的感觉)

    适用于任意组件间的通信;

    要在组件的componentWillUnmount中取消订阅;

  4. 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 })
    }
    

如果觉得博主的文章还不错的话
➕关注博主点赞文章收藏文章
✏️原创不易你的支持将会是我最大的动力
感谢观看

你可能感兴趣的:(React--从基础到实战,react.js,github,javascript,ajax,fetch)