摘要:中发布订阅模式使用场景怎么能将设计模式应用到我们的项目中以前一直在思考这个问题。两个模块在事件系统唯一的联系就是事先定义好事件的。
react 中发布订阅模式使用 场景
怎么能将设计模式应用到我们的 React 项目中?以前一直在思考这个问题。
场景一模块 A 模块 B 需要用到同一个数据 data,A 和 B 都会修改这份数据,且这两个模块会同时存在;这时我们如何做到数据公用与各个模块的更新?
方案一:
将这份数据作为公共的数据 data,A B 模块同时使用并更改这份数据这一份数据。若使用 redux 代码可能是这样:
// store const store = { common: { data: [] }, A: {}, B: {}, }; // reducer function commonReducer(state = { data: [] }, action) { switch (action.type) { case "common_setData": { return { ...state, data: action.data, }; } default: return state; } } // connect const actionCreator = () => {}; connect(({ A, common }) => ({ ...A, data: common.data }))(A); connect(({ B, common }) => ({ ...A, data: common.data }))(B); // change // A B change调用方法; this.props.dispatch({ type: "common_setData", data: [1, 2], });
好的,第一种场景可以使用 redux 完美解决
方案二:待补充
场景二A 模块使用了 data1, B 模块使用了 data2;A B 模块可以修改对应的 data;这两份 data 结构上不同,但是存在业务上的联系: 当 data1 更新后需要 data2 更新;data2 更新同样需要 data1 同步;对应后端的两个不同的 API。
我们整理一下
A B 使用两份存在联系的 data
其中一个更新需要另一个更新
两份 data 对应不同的 API 接口
A B 对应两个不同的 tab 且可能同时存在
方案一当其中一个数据因操作发生更新时,判断另一个模块是否存在 如果存在则调用他的数据更新逻辑;
如果你使用了 redux,可能方便一点:
// reducerA // 省略B function reducerA(state = { data: [] }, action) { switch(action.type) { case "A_setDataA": { return { ...state, data: action.data } } default: return state } } // 假设使用了thunk中间件 const queryA = () => async (dispatch, getState) => { const dataA = await API.queryA() dispatch({ type: "A_setDataA" data: dataA }) } // page class B extends React.Component { handleUpdateData = () => { // 如果 A模块存在 const { isAExistFlag, dispatch, queryA, queryB } = props dispatch(queryB()) if (isAExistFlag) { dispatch(queryA()) } } }
这样利用了 redux 可以实现功能,在模块 B 内调用模块 A 的更新逻辑;但这样逻辑就耦合了,我在模块 A 调用模块 B 方法 在模块 B 调用模块 A 的方法;但很有可能这两个模块是没有其他交互的。这违反了低耦合高内聚的原则
而且书写 redux 的一个原则就是 不要调用(dispatch)其他模块的 action
如果你不使用 redux 如果是一个模块内调用其他模块的方法也是没有做到解耦的;那如何做到解耦尼?请看方案二
方案二:利用事件系统如果您的项目中没有一个全局的事件系统,可能需要引入一个;一个简单的事件系统大概是:
class EventEmitter { constructor() { this.listeners = {}; } on(type, cb, mode) { let cbs = this.listeners[type]; if (!cbs) { cbs = []; } cbs.push(cb); this.listeners[type] = cbs; return () => { this.remove(type, cb); }; } emit(type, ...args) { console.log( `%c event ${type} be triggered`, "color:rgb(20,150,250);font-size:14px", ); const cbs = this.listeners[type]; if (Array.isArray(cbs)) { for (let i = 0; i < cbs.length; i++) { const cb = cbs[i]; if (typeof cb === "function") { cb(...args); } } } } remove(type, cb) { if (cb) { let cbs = this.listeners[type]; cbs = cbs.filter(eMap => eMap.cb !== cb); this.listeners[type] = cbs; } else { this.listeners[type] = null; delete this.listeners[type]; } } } export default new EventEmitter();
这个事件系统具有注册,发布,移除事件的功能。那我们怎么在刚才这个场景去使用它尼?
发布:当A模块内数据因操作发生变化时,触发该数据变化的事件,定义type为data1Change;
注册:这里B模块的注册的时机,上述的场景为A和B模块可能同时出现,所以A模块存在B模块却不存在。所以这个B模块事件的监听选择在B模块组件的componentDidMount的时候注册,在componentWillUnmount时移除
大致的代码如下:
import EventEmitter from "eventEmitter" class A extends React.Component { handleUpdateData = () => { // 如果 A模块存在 const { dispatch, queryB } = props dispatch(queryA()) EventEmitter.emit("data1Change") } } // B import EventEmitter from "eventEmitter" class B extends React.Component { componentDidMount() { const unlistener = EventEmitter.on("data1Change", this.handleData1Change) } componentWillUnmount() { EventEmitter.on("data1Change", this.handleData1Change) } handleData1Change = () => { const { dispatch, queryB } = this.props dispatch(queryB()) } }
这样通过事件系统做到了两个模块之间的解耦,作为事件发布方只管发布自己的事件。两个模块在事件系统唯一的联系就是事先定义好事件的type。
不过这也增加了几行的代码量,但相比带来的优势来说可以不计。
其他方案欢迎大家评论
其他场景待大家补充
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/99573.html
摘要:在我看来它们的关系不会比共用开头更深了,所以我就重新开了一个头,但其实是基于前面写的资源中文文档英文文档官方视频学习历程当初为了学习,看了许多的材料,中途曾经放弃两次,但是最后还是勇敢的拿起了它,现在终于勉强弄懂。 0x000 概述 这一章开始讲redux,其实是承接前面的react,但其实作为一个框架来说,redux和react并没有太多的关系,本身是独立存在的。在我看来它们的关系不...
摘要:通过发布订阅模式过滤数据现在我们已经把应用中比较敏感的代码放到了一些方法里面,我们还需要学习安全故事的另一半内容了。当在客户端被调用时传入发布器名称,客户端将会从发布器订阅所有的数据。这个按钮应该只是给任务的所有者来显示。 通过发布订阅模式过滤数据 现在我们已经把应用中比较敏感的代码放到了一些方法里面,我们还需要学习Meteor安全故事的另一半内容了。到现在为止,我们一直是假设整个整个...
摘要:同时吸取了社区大量优秀思想,进行归纳比对。有兴趣的读者可以点击下面的链接购买,再次感谢各位的支持与鼓励恳请各位批评指正京东当当原文网址 在React中最小的逻辑单元是组件,组件之间如果有耦合关系就会进行通信,本文将会介绍React中的组件通信的不同方式 通过归纳范,可以将任意组件间的通信归类为四种类型的组件间通信,分别是父子组件,爷孙组件,兄弟组件和任意组件,需要注意的是前三个也可以算...
摘要:下面我们会向大家解释清楚为什么这个这么重要,以及它和的响应式数据流有什么关系。源码前面铺垫这么多就是希望大家能理解接下来要讲的响应式数据流。总结讲到这里大家应该都能够明白的响应式数据流是如何实现的。 Vue、React介绍 目前前端社区比较推崇的框架有Vue 和 React,公司内部许多端都自发的将原有的老技术方案(widget + jQuery)迁移到 Vue / React上了。我...
阅读 881·2021-11-23 09:51
阅读 1088·2021-11-15 17:57
阅读 1667·2021-09-22 15:24
阅读 812·2021-09-07 09:59
阅读 2221·2019-08-29 15:10
阅读 1849·2019-08-29 12:47
阅读 751·2019-08-29 12:30
阅读 3369·2019-08-26 13:51