微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

⑥ React 项目中的AJAX请求、组件间通信的2种方式props、消息订阅和发布

查看专栏其它文章

① React 介绍及JSX简单使用

② React 面向组件编程(state、props、refs)、事件处理

③ React 条件渲染、组件生命周期、表单与事件

④ React 列表与Keys、虚拟DOM相关说明、AJAX

⑤ React 基于react脚手架构建简单项目


React


本人是个新手,写下博客用于自我复习、自我总结。
如有错误之处,请各位大佬指出。
学习资料来源于:尚硅谷


AJAX请求 (使用axios)

在之前的文章中已经介绍过这部分用法,想要回顾可参照我的第 ④ 篇文章,如果对具体AJAX的用法不熟悉,可以参考文章Ajax介绍以及工作原理和实现详解(JS实现Ajax 和 JQ实现Ajax)

因为推荐使用 axios,所以这里只用 axios 进行演示。在项目中使用的用法和之前相同。只不过需要注意,不要忘记在项目中先导入 axios:npm i axios --save

本次代码实现的功能如下图: ( 划分组件 )

在这里插入图片描述

根据划分组件,创建项目结构:(为方便已经简化,更具体的可参考我的第 ⑤ 篇文章

在这里插入图片描述

app 依然为根组件。

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/app'
import './index.css'

ReactDOM.render(<App />, document.getElementById('root'))

app.jsx

import React from 'react'
import Search from './search'
import UserList from './user-list'

export default class App extends React.Component {

  state = {
    searchName: ''
  }

  refreshName = (searchName) => this.setState({searchName})

  render() {
    return (
      <div className="container">
        <section className="jumbotron">
          <h3 className="jumbotron-heading">Search Github Users</h3>
          <Search refreshName={this.refreshName}/>
        </section>
        <UserList searchName={this.state.searchName}/>
      </div>
    )
  }
}

search.jsx

/**
 * 上部的搜索模块
 */
import React, {Component} from 'react'
import PropTypes from 'prop-types'

class Search extends Component {

  static propTypes = {
    refreshName: PropTypes.func.isrequired
  }

  search = () => {
    const name = this.nameInput.value.trim()
    if(name){
      this.props.refreshName(name)
    }
  }

  render() {
    return (
      <div>
        <input type="text" placeholder="enter the name you search"
               ref={(input => this.nameInput = input)}/>
        <button onClick={this.search}>Search</button>
      </div>
    )
  }
}

export default Search

user-list.jsx

/**
 * 下部的用户列表模块
 */
import React from 'react'
import PropTypes from 'prop-types'
import axios from 'axios'

class UserList extends React.Component {

  static propTypes = {
    searchName: PropTypes.string.isrequired
  }

  state = {
    firstView: true,
    loading: false,
    users: null,
    error: null
  }

  componentwillReceiveProps(nextProps)  {
    let searchName = nextProps.searchName
    console.log('发送ajax请求', searchName)
    const url = `https://api.github.com/search/users?q=${searchName}`
    this.setState({ firstView: false, loading: true })

    // 使用axios库
    axios.get(url)
      .then((response) => {
        console.log(response)
        this.setState({ loading: false, users: response.data.items })
      })
      .catch((error)=>{
        // debugger
        console.log('error', error.response.data.message, error.message)
        this.setState({ loading: false, error: error.message })
      })
  }

  render () {
    if (this.state.firstView) {
      return <h2>Enter name to search</h2>
    } else if (this.state.loading) {
      return <h2>Loading result...</h2>
    } else if (this.state.error) {
      return <h2>{this.state.error}</h2>
    } else {
      return (
        <div className="row">
          {
            this.state.users.map((user) => (
              <div className="card" key={user.html_url}>
                <a href={user.html_url} target="_blank">
                  <img src={user.avatar_url} style={{width: '100px'}} alt='user'/>
                </a>
                <p className="card-text">{user.login}</p>
              </div>
            ))
          }
        </div>
      )
    }
  }
}

export default UserList

在这里使用到了之前在生命周期中提到过的,componentwillReceiveProps()。这个勾子函数的使用也是比较频繁的,它的作用是:组件将要接收到新的props时回调。而在上面代码的整个过程中,只要从输入框中输入新数据搜索信息时,就会将该搜索内容通过props的方式传递给该组件,因此将axios请求放在其中,就是十分合适的。


组件间通信


方式一: 通过props传递

对于第一种方式应该已经不陌生了,在这里就不放代码了。测试语法时,所有组件传递用的都是 props。那在项目中,我们通常将共同的数据放在父组件上,特有的数据放在各自组件内部 (state)。然后涉及到数据传递,用的就是 props。

从目前来看,它的特点是:可以传递一般数据和函数数据,且只能一层一层传递


方式二: 使用消息订阅(subscribe)-发布(publish)机制

对于这种方式,想要使用需要下载: npm install pubsub-js --save

它的使用方法

import PubSub from 'pubsub-js' //引入

PubSub.subscribe('delete', function(data){ }); //订阅

PubSub.publish('delete', data) //发布消息

它和 props 那种需要一层一层传递的区别是:消息订阅-发布的方式可以做到直接传递

接下来的演示代码将对上面AJAX部分的代码进行修改

首先对于 app.jsx,之前的时候我们把共同的数据存放在父组件上,这样才能做到数据传递。但现在有了 消息订阅-发布的方式,我们已经不需要这么做了,现在可以做到直接传递:

import React from 'react'
import Search from './search'
import UserList from './user-list'

export default class App extends React.Component {
  render() {
    return (
      <div className="container">
        <section className="jumbotron">
          <h3 className="jumbotron-heading">Search Github Users</h3>
          <Search/>
        </section>
        <UserList/>
      </div>
    )
  }
}

然后对于搜索框组件 search.jsx,我们要将输入的数据传递给用户列表组件,去使用 axios 获取数据,此时我们只需 发布消息 即可。需要注意的是,消息名要和订阅消息时的消息名相同,比如在这里search。传递的消息是 searchName。

/**
 * 上部的搜索模块
 */
import React, {Component} from 'react'
import PubSub from 'pubsub-js'

class Search extends Component {

  search = () => {
    const searchName= this.nameInput.value.trim()
    if(searchName){
      //发布消息
      PubSub.publish('search', searchName)
    }
  }

  render() {
    return (
      <div>
        <input type="text" placeholder="enter the name you search"
               ref={(input => this.nameInput = input)}/>
        <button onClick={this.search}>Search</button>
      </div>
    )
  }
}

export default Search

因此,根据上述内容订阅消息时其消息名一定要为 search才能匹配。这里的msg不用管,其实代表的是消息名。在这里接收传递过来消息的参数名是 searchName。但这个参数名,不一定要和发布消息时的相同。

/**
 * 下部的用户列表模块
 */
import React from 'react'
import axios from 'axios'
import PubSub from 'pubsub-js'

class UserList extends React.Component {

  state = {
    firstView: true,
    loading: false,
    users: null,
    error: null
  }

  componentDidMount() {
    //订阅消息
    PubSub.subscribe('search',(msg,searchName) => {
      const url = `https://api.github.com/search/users?q=${searchName}`
      this.setState({ firstView: false, loading: true })
      // 使用axios库
      axios.get(url).then((response) => {
        this.setState({ loading: false, users: response.data.items })
      }).catch((error)=>{
        this.setState({ loading: false, error: error.message })
      })
    })
  }

  render () {
    if (this.state.firstView) {
      return <h2>Enter name to search</h2>
    } else if (this.state.loading) {
      return <h2>Loading result...</h2>
    } else if (this.state.error) {
      return <h2>{this.state.error}</h2>
    } else {
      return (
        <div className="row">
          {
            this.state.users.map((user) => (
              <div className="card" key={user.html_url}>
                <a href={user.html_url} target="_blank">
                  <img src={user.avatar_url} style={{width: '100px'}} alt='user'/>
                </a>
                <p className="card-text">{user.login}</p>
              </div>
            ))
          }
        </div>
      )
    }
  }
}

export default UserList

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐