React兄弟组件之间的通讯

案例要求:
在这里插入图片描述
达到这样一个效果

组件拆分:

  • 搜索框是一个组件,传递状态
  • 下面的展示列表是一个组件,使用状态

方式一:状态存在父组件之间

父组件传递给子组件消息可以使用props,子组件给父组件之间传递消息可以使用函数实现
APP组件代码

import React, { Component } from 'react'
import Search from './components/Search/Search'
import './App.css'
import List from './components/List/List'

export default class App extends Component {
    state={ //初始化状态,状态初始化时要初始化对
        items:[], //初始为数组
        isFirst:true,
        isLoading:false,
        err:''
    }
    getData=(items) => {
        this.setState({items:items})
    }
    setFirst=() => {
        this.setState({isFirst:false})
    }
    setLoading=() => {
        const {isLoading}=this.state
        // this.state.setState({isLoading:!this.state.isLoading})
        console.log(isLoading)
        this.setState({isLoading:!isLoading})
    }
    setErr=(errInfo) => {
        this.setState({err:errInfo})
    }
    render() {
        const {items,isFirst,isLoading,err}=this.state
        return (
            <div className="container">
                {/*这个地方传的时候可以一下子传一个对象,后面更改的时候只需传需要更改的字段就行,因为是覆盖的,不传就不会更改 */}
                <Search getData={this.getData} setFirst={this.setFirst} setLoading={this.setLoading} setErr={this.setErr}/> 
                <List items={items} isFirst={isFirst} isLoading={isLoading} err={err}/>
            </div>
        )
    }
}

search组件代码

import React, { Component } from 'react'
import axios from 'axios'
export default class Search extends Component {

    search=() => {
        //1、获取用户输入
        const {input:{value:keyword}}=this
        this.props.setFirst()
        this.props.setLoading() 
        this.props.setErr("")//每次请求之前把err清空
        //2、发送网络请求
        axios.get(`http://localhost:3000/api1/search/users?q=${keyword}`).then( //如果站的位置就是发送请求的位置,可以把http://localhost:3000省略
        //这里面只能写response和error
            response=>{
          //这里面不函数后面不能写,不然会被当做表达式,在这里面不能setLoading,为什么这里的函数调不了
                this.props.setLoading()
                this.props.getData(response.data.items)
                console.log('ccc')
            },
            error => {
                // console.log('失败了',error),
                this.props.setLoading()
                this.props.setErr(error)
            }
        )
    }
    render() {
        return (
            <section className="jumbotron">
                <h3 className="jumbotron-heading">搜索github用户</h3>
                <div>
                    <input ref={(currentNode) => {this.input=currentNode}} type="text" placeholder="输入关键词"/>&nbsp;
                    <button onClick={this.search}>搜索</button>
                </div>
            </section>
        )
    }
}

list组件代码

import React, { Component } from 'react'
import './List.css'
export default class List extends Component {
    render() {
        const {items}=this.props
        if (this.props.isFirst) {
            return <div><h2>欢迎来到该界面</h2></div>
        }
        if(this.props.isLoading){
            return <div><h2>Loading.....</h2></div>
        }
        if(this.props.err!==""){
            return <div><span>{this.props.err}</span></div>
        }
        return (
            <div className="row">
                {
                    items.map((item) => {
                        return (
                            <div className="card" key={item.id}>
                                <a href={item.html_url}>
                                    <img alt="head_picture" src={item.avatar_url} style={{width: '100px'}}></img>
                                </a>
                                <p className="card-text">{item.login}</p>
                            </div>                           
                        )
                    })
                }
             </div>
        )
    }
}

方式二:消息订阅,该方式为常用方式,方便简单

状态在操作组件中定义,消息在传递状态的组件中发布,在使用状态的组件中订阅。使用PubSubJS库实现消息订阅。
搜索框组件代码

import React, { Component } from 'react'
import axios from 'axios'
import PubSub from 'pubsub-js'
export default class Search extends Component {

  
        // //1、获取用户输入
        // const {input:{value:keyword}}=this
        // this.props.setFirst()
        // this.props.setLoading() 
        // this.props.setErr("")//每次请求之前把err清空
        // //2、发送网络请求
        // axios.get(`http://localhost:3000/api1/search/users?q=${keyword}`).then( //如果站的位置就是发送请求的位置,可以把http://localhost:3000省略
        // //这里面只能写response和error
        //     response=>{
        //   //这里面不函数后面不能写,不然会被当做表达式,在这里面不能setLoading,为什么这里的函数调不了
        //         this.props.setLoading()
        //         this.props.getData(response.data.items)
        //         console.log('ccc')
        //     },
        //     error => {
        //         // console.log('失败了',error),
        //         this.props.setLoading()
        //         this.props.setErr(error)
        //     }
        // )
        search=() => { 
            const {input:{value:keyword}}=this
            PubSub.publish('state',{isFirst:false,err:'',isLoading:true}) //发布消息
            axios.get(`http://localhost:3000/api1/search/users?q=${keyword}`).then(
                response => {
                    PubSub.publish('state',{isLoading:false,items:response.data.items})
                },
                error =>{
                    PubSub.publish('state',{isLoading:false,err:error})
                }
            )
    }
    render() {
        return (
            <section className="jumbotron">
                <h3 className="jumbotron-heading">搜索github用户</h3>
                <div>
                    <input ref={(currentNode) => {this.input=currentNode}} type="text" placeholder="输入关键词"/>&nbsp;
                    <button onClick={this.search}>搜索</button>
                </div>
            </section>
        )
    }
}

展示列表组件代码:

import React, { Component } from 'react'
import PubSub from 'pubsub-js'
import './List.css'
export default class List extends Component {
    state={ //初始化状态,状态初始化时要初始化对
        items:[], //初始为数组
        isFirst:true,
        isLoading:false,
        err:''
    }
    componentDidMount(){
        //组件挂载到页面后,该函数开启定时器或者订阅消息
        PubSub.subscribe('state',(_,data) => {
            //这里返回的token是供componentWillUnmount()关闭定时器或者取消订阅时候使用的
            this.token=this.setState(data) //data是一个状态对象,订阅消息后,当组件卸载的时候,还要取消订阅

        })
    }
    componentWillUnmount(){
        //组件即将卸载的时候,该函数关闭定时器,或者取消订阅
        PubSub.unsubscribe(this.token)
    }
    render() {
        const {isFirst,isLoading,err,items}=this.state
        {/**
        if (this.props.isFirst) {
            return <div><h2>欢迎来到该界面</h2></div>
        }
        if(this.props.isLoading){
            return <div><h2>Loading.....</h2></div>
        }
        if(this.props.err!==""){
            return <div><span>{this.props.err}</span></div>
        }
         return (
            <div className="row">
                {
                    items.map((item) => {
                        return (
                            <div className="card" key={item.id}>
                                <a href={item.html_url}>
                                    <img alt="head_picture" src={item.avatar_url} style={{width: '100px'}}></img>
                                </a>
                                <p className="card-text">{item.login}</p>
                            </div>                           
                        )
                    })
                }
             </div>
        )
         */}
        return (
            <div className="row">
            {
                //连着写的三元表达式,不能用if语句,因为jsx里面只能写js表达式,不能写js语句
                isFirst?<h2>欢迎使用,输入关键字,随后点击搜索</h2>:
                isLoading?<h2>Loading.....</h2>:
                err?<h2 style={{color:'red'}}>{err}</h2>:
                items.map((item) => {
                    return (
                        <div className="card" key={item.id}>
                            <a href={item.html_url}>
                                <img alt="head_picture" src={item.avatar_url} style={{width: '100px'}}></img>
                            </a>
                            <p className="card-text">{item.login}</p>
                        </div>                           
                    )
                })
            }
        </div>    
        )
        
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值