组件之间通讯常用方案
1、通过props
2、通过context
3、通过发布订阅模式
4、通过Redux 后面会有专栏介绍
1、安装 pubsub-js 插件 yarn add pubsub-js
常用的事件
a、发布事件:传入一个自定义事件名称(name
),以及要发布的消息内容(message
)Pubsub.publish('name', 'message')
还可以进行异步发布 Pubsub.publishSync('name', 'message')
b、订阅事件:传入发布事件的的名称 (name
),以及接收name事件传递参数的回调函数 callback
,最终会返回一个类似setTimeout 的timer 用于标记当前订阅的事件,在取消订阅时候可以之间传入此值 let sub0 = Pubsub.subscribe('name', callback)
c、取消订阅
Pubsub.unsubscribe('name')
// 可以传入发布事件名称进行取消
Pubsub.unsubscribe(sub0)
// 还可以传入 订阅事件返回的标识进行取消
2、在发布事件组件中引入
相对于自定义的发布订阅器要简单一些
可以同时发布多个事件
// 引入插件
import PubSub from 'pubsub-js'
export default function ChildA() {
const handlePublish = () => {
// 调用发布事件
PubSub.publish('onChangeName', '修改名称')
}
return (
<div style={{background:'blue'}}>
<h3>组件A</h3>
<button onClick={handlePublish}>发布</button>
</div>
)
}
3、在订阅组件中使用
可以订阅多个事件,取消多个事件
import { useEffect, useState } from "react"
import PubSub from "pubsub-js"
export default function ChildB() {
const [name, setName] = useState('')
const handleEvents = (fncName, data) => {
/***
* @description 回调函数接收两个参数
* @param {String} fncName 发布的函数名称,例如:onChangeName
* @param {any} data 发布传递的数据消息
* */
console.log('=msg==', fncName, data)
// 通过 useState 的set 函数进行视图更新
setName(data)
}
useEffect(() => {
// 订阅事件
let token1 = PubSub.subscribe('onChangeName',handleEvents)
return () => {
PubSub.unsubscribe('onChangeName') // 卸载时解除订阅
// 两种卸载时候取消订阅方案
// PubSub.unsubscribe('token1') // 卸载时解除订阅
}
}, [])
return (
<div>
<h3>组件B</h3>
<p>组件A传递消息: {name}</p>
</div>
)
}
4、在父组件中使用
import ChildA from './childA'
import ChildB from './childB'
export default function MyPubsub() {
return (
<div style={{background: 'red', padding: '12px', width: '360px', height: '500px'}}>
<h2>父组件</h2>
<ChildA></ChildA>
<hr />
{/* 完全独立的两个子组件 */}
<ChildB></ChildB>
</div>
)
}
注意:
a、不管是自定义发布订阅器,还是直接使用插件,在组件卸载时候,都有将当前组件的订阅取消,避免过多订阅运行,导致内存溢出
;
b、使用插件,相对更加方便简洁,只需要关注及时调用 api既可以,不需要注意发布订阅器里面的逻辑
c、要避免多状态,多个发布订阅器存在多组件中,会在出现bug时候造成难以追踪定位问题点;