摘要:中發(fā)布訂閱模式使用場(chǎng)景怎么能將設(shè)計(jì)模式應(yīng)用到我們的項(xiàng)目中以前一直在思考這個(gè)問題。兩個(gè)模塊在事件系統(tǒng)唯一的聯(lián)系就是事先定義好事件的。
react 中發(fā)布訂閱模式使用 場(chǎng)景
怎么能將設(shè)計(jì)模式應(yīng)用到我們的 React 項(xiàng)目中?以前一直在思考這個(gè)問題。
場(chǎng)景一模塊 A 模塊 B 需要用到同一個(gè)數(shù)據(jù) data,A 和 B 都會(huì)修改這份數(shù)據(jù),且這兩個(gè)模塊會(huì)同時(shí)存在;這時(shí)我們?nèi)绾巫龅綌?shù)據(jù)公用與各個(gè)模塊的更新?
方案一:
將這份數(shù)據(jù)作為公共的數(shù)據(jù) data,A B 模塊同時(shí)使用并更改這份數(shù)據(jù)這一份數(shù)據(jù)。若使用 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調(diào)用方法; this.props.dispatch({ type: "common_setData", data: [1, 2], });
好的,第一種場(chǎng)景可以使用 redux 完美解決
方案二:待補(bǔ)充
場(chǎng)景二A 模塊使用了 data1, B 模塊使用了 data2;A B 模塊可以修改對(duì)應(yīng)的 data;這兩份 data 結(jié)構(gòu)上不同,但是存在業(yè)務(wù)上的聯(lián)系: 當(dāng) data1 更新后需要 data2 更新;data2 更新同樣需要 data1 同步;對(duì)應(yīng)后端的兩個(gè)不同的 API。
我們整理一下
A B 使用兩份存在聯(lián)系的 data
其中一個(gè)更新需要另一個(gè)更新
兩份 data 對(duì)應(yīng)不同的 API 接口
A B 對(duì)應(yīng)兩個(gè)不同的 tab 且可能同時(shí)存在
方案一當(dāng)其中一個(gè)數(shù)據(jù)因操作發(fā)生更新時(shí),判斷另一個(gè)模塊是否存在 如果存在則調(diào)用他的數(shù)據(jù)更新邏輯;
如果你使用了 redux,可能方便一點(diǎn):
// reducerA // 省略B function reducerA(state = { data: [] }, action) { switch(action.type) { case "A_setDataA": { return { ...state, data: action.data } } default: return state } } // 假設(shè)使用了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 可以實(shí)現(xiàn)功能,在模塊 B 內(nèi)調(diào)用模塊 A 的更新邏輯;但這樣邏輯就耦合了,我在模塊 A 調(diào)用模塊 B 方法 在模塊 B 調(diào)用模塊 A 的方法;但很有可能這兩個(gè)模塊是沒有其他交互的。這違反了低耦合高內(nèi)聚的原則
而且書寫 redux 的一個(gè)原則就是 不要調(diào)用(dispatch)其他模塊的 action
如果你不使用 redux 如果是一個(gè)模塊內(nèi)調(diào)用其他模塊的方法也是沒有做到解耦的;那如何做到解耦尼?請(qǐng)看方案二
方案二:利用事件系統(tǒng)如果您的項(xiàng)目中沒有一個(gè)全局的事件系統(tǒng),可能需要引入一個(gè);一個(gè)簡(jiǎn)單的事件系統(tǒng)大概是:
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();
這個(gè)事件系統(tǒng)具有注冊(cè),發(fā)布,移除事件的功能。那我們?cè)趺丛趧偛胚@個(gè)場(chǎng)景去使用它尼?
發(fā)布:當(dāng)A模塊內(nèi)數(shù)據(jù)因操作發(fā)生變化時(shí),觸發(fā)該數(shù)據(jù)變化的事件,定義type為data1Change;
注冊(cè):這里B模塊的注冊(cè)的時(shí)機(jī),上述的場(chǎng)景為A和B模塊可能同時(shí)出現(xiàn),所以A模塊存在B模塊卻不存在。所以這個(gè)B模塊事件的監(jiān)聽選擇在B模塊組件的componentDidMount的時(shí)候注冊(cè),在componentWillUnmount時(shí)移除
大致的代碼如下:
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()) } }
這樣通過事件系統(tǒng)做到了兩個(gè)模塊之間的解耦,作為事件發(fā)布方只管發(fā)布自己的事件。兩個(gè)模塊在事件系統(tǒng)唯一的聯(lián)系就是事先定義好事件的type。
不過這也增加了幾行的代碼量,但相比帶來的優(yōu)勢(shì)來說可以不計(jì)。
其他方案歡迎大家評(píng)論
其他場(chǎng)景待大家補(bǔ)充
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/99573.html
摘要:在我看來它們的關(guān)系不會(huì)比共用開頭更深了,所以我就重新開了一個(gè)頭,但其實(shí)是基于前面寫的資源中文文檔英文文檔官方視頻學(xué)習(xí)歷程當(dāng)初為了學(xué)習(xí),看了許多的材料,中途曾經(jīng)放棄兩次,但是最后還是勇敢的拿起了它,現(xiàn)在終于勉強(qiáng)弄懂。 0x000 概述 這一章開始講redux,其實(shí)是承接前面的react,但其實(shí)作為一個(gè)框架來說,redux和react并沒有太多的關(guān)系,本身是獨(dú)立存在的。在我看來它們的關(guān)系不...
摘要:通過發(fā)布訂閱模式過濾數(shù)據(jù)現(xiàn)在我們已經(jīng)把應(yīng)用中比較敏感的代碼放到了一些方法里面,我們還需要學(xué)習(xí)安全故事的另一半內(nèi)容了。當(dāng)在客戶端被調(diào)用時(shí)傳入發(fā)布器名稱,客戶端將會(huì)從發(fā)布器訂閱所有的數(shù)據(jù)。這個(gè)按鈕應(yīng)該只是給任務(wù)的所有者來顯示。 通過發(fā)布訂閱模式過濾數(shù)據(jù) 現(xiàn)在我們已經(jīng)把應(yīng)用中比較敏感的代碼放到了一些方法里面,我們還需要學(xué)習(xí)Meteor安全故事的另一半內(nèi)容了。到現(xiàn)在為止,我們一直是假設(shè)整個(gè)整個(gè)...
摘要:同時(shí)吸取了社區(qū)大量?jī)?yōu)秀思想,進(jìn)行歸納比對(duì)。有興趣的讀者可以點(diǎn)擊下面的鏈接購買,再次感謝各位的支持與鼓勵(lì)懇請(qǐng)各位批評(píng)指正京東當(dāng)當(dāng)原文網(wǎng)址 在React中最小的邏輯單元是組件,組件之間如果有耦合關(guān)系就會(huì)進(jìn)行通信,本文將會(huì)介紹React中的組件通信的不同方式 通過歸納范,可以將任意組件間的通信歸類為四種類型的組件間通信,分別是父子組件,爺孫組件,兄弟組件和任意組件,需要注意的是前三個(gè)也可以算...
摘要:下面我們會(huì)向大家解釋清楚為什么這個(gè)這么重要,以及它和的響應(yīng)式數(shù)據(jù)流有什么關(guān)系。源碼前面鋪墊這么多就是希望大家能理解接下來要講的響應(yīng)式數(shù)據(jù)流??偨Y(jié)講到這里大家應(yīng)該都能夠明白的響應(yīng)式數(shù)據(jù)流是如何實(shí)現(xiàn)的。 Vue、React介紹 目前前端社區(qū)比較推崇的框架有Vue 和 React,公司內(nèi)部許多端都自發(fā)的將原有的老技術(shù)方案(widget + jQuery)遷移到 Vue / React上了。我...
摘要:標(biāo)簽添加監(jiān)聽事件文本節(jié)點(diǎn)這一步我們操作頁面輸入框,可以看到以下效果,證明監(jiān)聽事件添加有效。 前言 經(jīng)過幾天的研究,發(fā)現(xiàn)學(xué)習(xí)框架的底層技術(shù),收獲頗豐,相比只學(xué)習(xí)框架的使用要來的合算;如果工作急需,快速上手應(yīng)用,掌握如何使用短期內(nèi)更加高效;如果有較多的時(shí)間來系統(tǒng)學(xué)習(xí),建議研究一下框架的等層技術(shù)、原理。 Vue、React、Angular三大框架對(duì)比 1、Vue Vue是尤雨溪編寫的一個(gè)構(gòu)建...
閱讀 960·2021-11-23 09:51
閱讀 1205·2021-11-15 17:57
閱讀 1719·2021-09-22 15:24
閱讀 866·2021-09-07 09:59
閱讀 2299·2019-08-29 15:10
閱讀 1907·2019-08-29 12:47
閱讀 819·2019-08-29 12:30
閱讀 3457·2019-08-26 13:51