React学习(6)消息订阅发布

组件间通信

  • 方式一: 通过props传递
    1) 共同的数据放在父组件上, 特有的数据放在自己组件内部(state)
    2) 通过props可以传递一般属性和函数属性, 只能一层一层传递
    3) 一般属性–>父组件传递数据给子组件–>子组件读取数据
    4) 函数属性–>子组件传递数据给父组件–>子组件调用函数
  • 方式二: 使用消息订阅(subscribe)-发布(publish)机制
    1) 工具库: PubSubJS
    2) 下载: npm install pubsub-js --save
    3) 使用:

import PubSub from 'pubsub-js' //引入
PubSub.subscribe('delete', function(data){ }); //订阅
PubSub.publish('delete', data) //发布消息
  • 方式三: redux
    省略

DEMO:获取github用户信息

实现效果

通过props传递实现

  • App.jsx代码如下:
import React, {Component} from "react"
import Search from './components/Search/Search'
import List from './components/List/List'

export default class App extends Component {
    state = {
        keyword: ''
    }

    setKeyWord = (keyword) => {
        this.setState({keyword})
    }

    render() {
        let {keyword} = this.state
        return (
            <div className="container">
                <Search setKeyWord={this.setKeyWord}/>
                <List keyword={keyword}/>
            </div>
        )
    }
}
  • components/Search/Search.jsx代码如下:
import React, {Component} from "react";

export default class Search extends Component {
    search = () => {
        let {keyword} = this
        let {setKeyWord} = this.props
        keyword = keyword.value
        setKeyWord(keyword)
        this.keyword.value = ''
    }

    render() {
        return (
            <section className="jumbotron">
                <h3 className="jumbotron-heading">Search Github Users</h3>
                <div>
                    <input type="text" placeholder="enter the name you search" ref={(input)=>{this.keyword = input}}/>
                    <button onClick={this.search}>Search</button>
                </div>
            </section>
        );
    }
}
  • components/List/List.jsx代码如下:
import React, {Component} from "react";
import Item from '../Item/Item'
import axios from "axios";

export default class List extends Component {
    state = {
        isLoading: false,
        users: [],
        errMsg: ''
    }

    async componentWillReceiveProps({keyword}) {
        this.setState({
            isLoading: true,
        })
        const url = `https://api.github.com/search/users?q=${keyword}`
        try {
            let response = await axios.get(url)
            let users =  response.data.items.map((item, index) => {
                return {
                    id: item.id,
                    html_url: item.html_url,
                    avatar_url: item.avatar_url,
                    user_name: item.login
                }
            })
            this.setState({
                isLoading: false,
                users
            })
        } catch (err) {
            this.setState({
                isLoading: false,
                errMsg: err.toString()
            })
        }
    }

    render() {
        let {isLoading,users,errMsg} = this.state

        if (users.length > 0) {
            return (
                <div className="row">
                    {
                        users.map((item) => {
                            console.log(item)
                            return <Item key={item.id} {...item}/>
                        })
                    }
                </div>
            );
        } else {
            if (isLoading) {
                return <h2>Loading...</h2>
            } else if (errMsg) {
                return <h2>{errMsg}</h2>
            } else {
                return <h2>Enter name to search</h2>
            }

        }
    }
}
  • components/Item/Item.jsx代码如下:
import React, {Component} from "react";
import './Item.css'

export default class Item extends Component {
    render() {
        let {html_url,avatar_url,user_name} = this.props
        return (
            <div className="card ">
                <a href={html_url} rel="noopener noreferrer" target="_blank">
                    <img alt="" src={avatar_url} style={{width: '100px'}}/>
                </a>
                <p className="card-text">{user_name}</p>
            </div>
        );
    }
}

通过消息订阅机制实现

  • App.jsx代码如下:
import React, {Component} from "react"
import Search from './components/Search/Search'
import List from './components/List/List'

export default class App extends Component {
    render() {
        return (
            <div className="container">
                <Search/>
                <List/>
            </div>
        )
    }
}
  • components/Search/Search.jsx代码如下:
import React, {Component} from "react";
import PubSub from "pubsub-js";
import axios from "axios";

export default class Search extends Component {
    search = async () => {
        //获取用户输入
        let keyword = this.keyword.value.trim()

        //设置loading状态
        PubSub.publish('updateListState',{isLoading: true,users: [],errMsg: ''})

        //发送请求
        const url = `https://api.github.com/search/users?q=${keyword}`
        try {
            let response = await axios.get(url)
            let users =  response.data.items.map((item, index) => {
                return {
                    id: item.id,
                    html_url: item.html_url,
                    avatar_url: item.avatar_url,
                    user_name: item.login
                }
            })
            PubSub.publish('updateListState',{isLoading: false,users,errMsg: ''})
        } catch (err) {
            PubSub.publish('updateListState',{isLoading: false,users:[],errMsg: err.toString()})
        }

        this.keyword.value = ''
    }

    render() {
        return (
            <section className="jumbotron">
                <h3 className="jumbotron-heading">Search Github Users</h3>
                <div>
                    <input type="text" placeholder="enter the name you search" ref={(input)=>{this.keyword = input}}/>
                    <button onClick={this.search}>Search</button>
                </div>
            </section>
        );
    }
}
  • components/List/List.jsx代码如下:
import React, {Component} from "react";
import Item from '../Item/Item'
import PubSub from 'pubsub-js'

export default class List extends Component {
    state = {
        isLoading: false,
        users: [],
        errMsg: ''
    }

    componentDidMount() {
        PubSub.subscribe('updateListState',(msg,{isLoading,users,errMsg})=>{
            this.setState({
                isLoading,
                users,
                errMsg,
            })
        })
    }

    render() {
        let {isLoading,users,errMsg} = this.state

        if (users.length > 0) {
            return (
                <div className="row">
                    {
                        users.map((item) => {
                            console.log(item)
                            return <Item key={item.id} {...item}/>
                        })
                    }
                </div>
            );
        } else {
            if (isLoading) {
                return <h2>Loading...</h2>
            } else if (errMsg) {
                return <h2>{errMsg}</h2>
            } else {
                return <h2>Enter name to search</h2>
            }

        }

    }
}
  • components/Item/Item.jsx代码如下:
import React, {Component} from "react";
import './Item.css'

export default class Item extends Component {
    render() {
        let {html_url,avatar_url,user_name} = this.props
        return (
            <div className="card ">
                <a href={html_url} rel="noopener noreferrer" target="_blank">
                    <img alt="" src={avatar_url} style={{width: '100px'}}/>
                </a>
                <p className="card-text">{user_name}</p>
            </div>
        );
    }
}

发表评论

邮箱地址不会被公开。 必填项已用*标注