react 中宣布定阅形式运用

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();

这个事宜体系具有注册,宣布,移除事宜的功用。那我们怎样在适才这个场景去运用它尼?

  1. 宣布:当A模块内数据因操纵发作变化时,触发该数据变化的事宜,定义typedata1Change
  2. 注册:这里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。

不过这也增加了几行的代码量,但比拟带来的上风来讲能够不计。

其他计划迎接人人批评

其他场景

待人人补充

    原文作者:fall_wind
    原文地址: https://segmentfault.com/a/1190000017194450
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞