EventBus可以适用于任何情况的组件通信,在项目规模不大的情况下,完全可以使用中央事件总线EventBus 的方式,EventBus可以比较完美地解决包括父子组件、兄弟组件、隔代组件之间通信,实际上就是一个观察者模式,观察者模式建立了一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。所以发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。首先我们需要实现一个订阅发布类作为单例模块导出,每个需要的组件再进行import,当然作为Mixins全局静态横切也可以,或者使用event库,此外务必注意在组件销毁的时候卸载订阅的事件调用,否则会造成内存泄漏。
// event-bus.js var PubSub = function() { this.handlers = {}; } PubSub.prototype = { constructor: PubSub, on: function(key, handler) { // 订阅 if(!(key in this.handlers)) this.handlers[key] = []; if(!this.handlers[key].includes(handler)) { this.handlers[key].push(handler); return true; } return false; }, once: function(key, handler) { // 一次性订阅 if(!(key in this.handlers)) this.handlers[key] = []; if(this.handlers[key].includes(handler)) return false; const onceHandler = (...args) => { handler.apply(this, args); this.off(key, onceHandler); } this.handlers[key].push(onceHandler); return true; }, off: function(key, handler) { // 卸载 const index = this.handlers[key].findIndex(item => item === handler); if (index < 0) return false; if (this.handlers[key].length === 1) delete this.handlers[key]; else this.handlers[key].splice(index, 1); return true; }, commit: function(key, ...args) { // 触发 if (!this.handlers[key]) return false; console.log(key, "Execute"); this.handlers[key].forEach(handler => handler.apply(this, args)); return true; }, } export default new PubSub(); <!-- 子组件 --> import React from "react"; import eventBus from "./event-bus"; class Child extends React.PureComponent{ render() { return ( <> <div>接收父组件的值: {this.props.msg}</div> <button onClick={() => eventBus.commit("ChangeMsg", "Changed Msg")}>修改父组件的值</button> </> ) } } export default Child; <!-- 父组件 --> import React from "react"; import Child from "./child"; import eventBus from "./event-bus"; class Parent extends React.PureComponent{ constructor(props){ super(props); this.state = { msg: "Parent Msg" }; this.child = React.createRef(); } changeMsg = (msg) => { this.setState({ msg }); } componentDidMount(){ eventBus.on("ChangeMsg", this.changeMsg); } componentWillUnmount(){ eventBus.off("ChangeMsg", this.changeMsg); } render() { return ( <div> <Child msg={this.state.msg} ref={this.child} /> </div> ) } } export default Parent; ReduxRedux同样可以适用于任何情况的组件通信,Redux中提出了单一数据源Store用来存储状态数据,所有的组件都可以通过Action修改Store,也可以从Store中获取最新状态,使用了redux就可以解决多个组件的共享状态管理以及组件之间的通信问题。
import { createStore } from "redux"; /** * 这是一个 reducer,形式为 (state, action) => state 的纯函数。 * 描述了 action 如何把 state 转变成下一个 state。 * * state 的形式取决于你,可以是基本类型、数组、对象、 * 甚至是 Immutable.js 生成的数据结构。惟一的要点是 * 当 state 变化时需要返回全新的对象,而不是修改传入的参数。 * * 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper) * 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。 */ function counter(state = 0, action) { switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } } // 创建 Redux store 来存放应用的状态。 // API 是 { subscribe, dispatch, getState }。 let store = createStore(counter); // 可以手动订阅更新,也可以事件绑定到视图层。 store.subscribe(() => console.log(store.getState())); // 改变内部 state 惟一方法是 dispatch 一个 action。 // action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行 store.dispatch({ type: "INCREMENT" }); // 1 store.dispatch({ type: "INCREMENT" }); // 2 store.dispatch({ type: "DECREMENT" }); // 1 每日一题 https://github.com/WindrunnerMax/EveryDay 参考 https://zhuanlan.zhihu.com/p/76996552 https://www.jianshu.com/p/fb915d9c99c4 https://juejin.cn/post/6844903828945387528 https://segmentfault.com/a/1190000023585646 https://github.com/andyChenAn/frontEnd/issues/46 https://blog.csdn.net/weixin_42262436/article/details/88852369