资讯专栏INFORMATION COLUMN

React入门0x012: 组件通信

Tonny / 2665人阅读

摘要:可以看到,父级更新了,子组件也同步更新了,也就完成了父组件向子组件发起通信的目的。当然我们也可以通过适当的组件设计来避免过深的组件嵌套通信。所以这就解决了远程组件通信深度组件嵌套的问题。组件间通信可以选择像这样的库来处理。

0x000 概述

这一章讲组件间通信,组件通信分为很多种:

父组件向子组件发起通信

子组件向父组件发起通信

兄弟组件间通讯

远程组件通信

在组件通信中,有一种错误的说法,那就是父组件调用子组件,子组件调用父组件,这种说法其实是错误的,并没有什么父组件调用子组件,这是一种传统的说法,从传统dom的操作方式来的,但是在react中,使用这种方法描述组件间的通信是不合适的。在我看来,用事件通知模型来描述可能更合适。

0x001 父组件向子组件发起通信
父组件向子组件发起通信很简单,直接使用props
import React from "react"
import ReactDom from "react-dom"

class Sub extends React.Component {
    constructor() {
        super()
        this.state = {
            num: 0
        }
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            num: nextProps.num
        })
    }

    render() {
        return 

props.num:{this.props.num}

state.num:{this.state.num}

} } class App extends React.Component { constructor() { super() this.state = { num: 0 } setInterval(() => { this.setState({ num: ++this.state.num }) }, 1000) } render() { return } } ReactDom.render( , document.getElementById("app") )

查看浏览器:

说明:App组件每秒更新一次num,同时将num通过props传递给子组件SubSub通过props访问父级传递下来的num,并渲染到界面上,同时也将该参数保存到自己的state中,也渲染到界面上。可以看到,父级更新了num,子组件也同步更新了,也就完成了父组件向子组件发起通信的目的。

0x002 子组件向父组件发起通信

子组件向父组件发起通信则是通过事件触发,我们可以想想平时的html

我们给button绑定了click事件,所以当我们点击按钮的时间,该事件就会被触发,然后执行我们的函数ourFunc并传递参数"you click me",这就是事件通知。现在我们假设button是我们实现的自定义组件,那么onclick就是我们传递的props。众所周知,js中,函数也是变量,所以在react中,props也可以传递函数:

import React from "react"
import ReactDom from "react-dom"

class MyButton extends React.Component {
    constructor() {
        super()
        this.state = {
            num: 0
        }
    }

    handleOnClick() {
        let num = ++this.state.num
        this.setState({
            num: num
        })
        this.props.onClick(num)
    }

    render() {
        return 
    }
}

class App extends React.Component {
    constructor() {
        super()
        this.state = {
            num: 0
        }
    }

    render() {
        return 

点击了 {this.state.num} 次

this.handleOnClick(text)}/>
} handleOnClick(num) { this.setState({ num: num }) } } ReactDom.render( , document.getElementById("app") )

查看浏览器:

说明:我们声明了一个MyButton组件,并传递了两个属性,一个是text,一个是onClick,注意,这里的onClick只是一个名字叫做onClick的属性,而不是点击事件,只是我们借用了这个名字而已,真正的点击事件必须绑定在dom上。所以这里叫什么名字都无所谓,不过为了好看,还是叫着名字比较好。
MyButton中,我们真正的绑定了onClick事件,并在该事件触发的时候,调用传递过来的props.onClick,并吧点击的次数作为参数,这样,ApphandleOnClick就会被促发,同时接收到num参数,用于显示用户的点击次数。
从表面上看,我们就好像在MyButton上绑定了事件一般,和web中的十分类似,但是这种机制更加的灵活,比如我们不一定要叫onClick,我们可以将之和业务绑定,叫做onUserAdd,这样,似乎就实现了自定义事件,并且具有一定的业务特点,非常的灵活。

0x003 兄弟组件通信
兄弟组件通信其实很简单,借助公共的父组件作为中间桥梁,然后通过上面说的props和事件机制,就完成了兄弟组件的通信,
稍微修改一下0x002的栗子就可以搞定了
class MyView extends React.Component {
    render() {
        return 

点击了 {this.props.num} 次

} } class MyButton extends React.Component { constructor() { super() this.state = { num: 0 } } handleOnClick() { let num = ++this.state.num this.setState({ num: num }) this.props.onClick(num) } render() { return } } class App extends React.Component { constructor() { super() this.state = { num: 0 } } render() { return
this.handleOnClick(text)}/>
} handleOnClick(num) { this.setState({ num: num }) } } ReactDom.render( , document.getElementById("app") )

查看浏览器:

说明:MyButtonMyView是挂载在App的子组件,他们是同级的兄弟组件,而他们之间的通信可以借助App作为中转,将数据从一个MyButton传递到MyView。具体过程:

MyButton点击事件触发后触发父组件传递进来的onClick

App监听MyButtononClick事件并将该事件的num保存到自己的state

state.num又传递到了MyView

所以当我们点击按钮的时候,点击次数就增加了。

0x004 远程组件通信

从上克制,组件间的通信可以通过props传递普通变量和函数来实现,但是如果事件嵌套的层级太深,这套模型就显得麻烦,必须要不断的传递props,不但冗余而且不好维护。
当然我们也可以通过适当的组件设计来避免过深的组件嵌套通信。
那如果无法避免呢?
那就需要用其他方式来实现了,比如,使用订阅-发布模型可以实现无视距离和组件的通信,甚至无视框架和位置,但是很容易引起混乱,适用于全局通知。
以下是简单实现:

实现通用的订阅-发布模型框架

let eventMap = {}

class MyEvent {

    static pub(name, data) {
        if (!eventMap.hasOwnProperty(name)) return
        let callbacks = eventMap[name]
        if (callbacks.length === 0) return
        callbacks.forEach((callback) => {
            callback(data)
        })


    }

    static sub(name, callback) {
        let callbacks = []
        if (eventMap.hasOwnProperty(name)) {
            callbacks = eventMap[name]
        }
        callbacks.push(callback)
        eventMap[name] = callbacks
    }
}

export default MyEvent

该框架只有两个方法,和一个事件队列,pub用来发布一个事件,sub用来订阅一个事件,调用pub发布一个事件以后,sub了该事件的方法就会被执行

MyEvent.sub("EventA",(data)=>{console.log(data)})
MyEvent.pub("EventA",{num:1})
// 查看控制台
{num:1}

编写组件

const EVENT_BUTTON_CLICK = "EVENT_BUTTON_CLICK"

class MyView extends React.Component {
    constructor() {
        super()
        this.state = {
            num: 0
        }
        MyEvent.sub(EVENT_BUTTON_CLICK, (num) => {
            this.setState({
                num: num.num
            })
        })

    }

    render() {
        return 

点击了 {this.state.num} 次

} } class MyButton extends React.Component { constructor() { super() this.state = { num: 0 } } handleOnClick() { let num = ++this.state.num this.setState({ num: num }) MyEvent.pub(EVENT_BUTTON_CLICK, {num: num}) } render() { return } } class App extends React.Component { constructor() { super() } render() { return
} } ReactDom.render( , document.getElementById("app") )

可以看到,我们使用的是发布-订阅模型,并没有通过父组件来做兄弟组件的传递中介,没有太多的props嵌套。所以这就解决了远程组件通信、深度组件嵌套的问题。当然也带来了另一个问题,那就是事件维护。如果事件太多,将会导致无法维护和流程混乱......不可乱用,可用于系统的中心事件控制,也就是单一的事件源输出。

组件间通信可以选择像redux这样的库来处理。

0x005 资源

react

源码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97250.html

相关文章

  • es6基础0x012:Map

    摘要:概述也是一个新的数据结构,在中其实也经常用到,比如下面的栗子,我们经常这么使用一个对象,与其说他是对象,其实他更像一个,但是比起真正的,这个还是有点弱了,初始化初始化一个有一个可选的参数,该参数必须是一个可迭代对象,可迭代对象包括和用户定 0x000 概述 Map也是一个新的数据结构,在js中其实也经常用到,比如下面的栗子,我们经常这么使用一个对象,与其说他是对象,其实他更像一个Map...

    DesGemini 评论0 收藏0
  • React 入门学习笔记整理目录

    摘要:入门学习笔记整理一搭建环境入门学习笔记整理二简介与语法入门学习笔记整理三组件入门学习笔记整理四事件入门学习笔记整理五入门学习笔记整理六组件通信入门学习笔记整理七生命周期入门学习笔记整理八入门学习笔记整理九路由React 入门学习笔记整理(一)——搭建环境 React 入门学习笔记整理(二)—— JSX简介与语法 React 入门学习笔记整理(三)—— 组件 React 入门学习笔记整理(...

    daryl 评论0 收藏0
  • 本命年一定要记得穿红裤衩:2015年总结

    摘要:年终总结结果到这个时间才写,其实也是无奈。这一年最重要的事情就是顺利从一只学生狗转职为一只社畜。四月份毕业之后以前端工程师的职位入职天猫,到现在也差不多工作一年了。 年终总结结果到这个时间才写,其实也是无奈。本来计划过年写的,没想到Steam竟然开了个农历春节特惠,然后就被各种游戏打了,辣鸡平台,敛我钱财,颓我精神,耗我青春,害我单身 以下全都是个人看法,如果有不认同的地方,请大吼一声...

    AlienZHOU 评论0 收藏0
  • 本命年一定要记得穿红裤衩:2015年总结

    摘要:年终总结结果到这个时间才写,其实也是无奈。这一年最重要的事情就是顺利从一只学生狗转职为一只社畜。四月份毕业之后以前端工程师的职位入职天猫,到现在也差不多工作一年了。 年终总结结果到这个时间才写,其实也是无奈。本来计划过年写的,没想到Steam竟然开了个农历春节特惠,然后就被各种游戏打了,辣鸡平台,敛我钱财,颓我精神,耗我青春,害我单身 以下全都是个人看法,如果有不认同的地方,请大吼一声...

    xi4oh4o 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<