1.Background
现有 APP 底部有 4 个 Tab 栏,Tabs 被一个类似 Frame 的页面包着,为了考虑性能与减少网络请求次数,只是首次进入会加载会 Tab 里的数据,所以QA与用户疯狂切 Tab,都是不请求数据,也不 rerender,真的如丝般顺滑。
2.New feature
好景不长,有一个带状态的列表要加入Tab 栏里来,列表有类似于「已购买」、「未购买」的状态,我们在详情页购买了,返回来要更新列表。
3.Motivation
第一时间想到的是 Redux ?很好,还有不同方案吗?对,就是 EventEmitter。
Redux 已经在我们现有项目中大量使用,已经觉得很无趣了。我们试试EventEmitter 怎么样? Node.js 源码里有很多地方都会使用 EventEmitter,例如:net.Server
会在每次有新连接时触发事件,fs.ReadStream
会在打开文件时触发事件,stream 会在数据可读时触发事件等。
我们为何不也学习一下呢? Come on, go ahead
4.Code
A、React Native 中的用法
1、在项目入口文件处引用 import EventEmitter from 'EventEmitter';
,React Native 已经内置了这个类,源码地址:node_modules/react-native/Libraries/vendor/emitter/EventEmitter.js
2、在项目入口文件(如:app.js 或 index.js)的 componentDidMount 里添加 global.CustomEventEmitter = new EventEmitter();
3、在 Tab 页的 componentDidMount
里添加 Listener,global.CustomEventEmitter.addListener
('tabListClick', this.getLatestData);
4、在 Tab 页的 componentWillUnmount
里删除 Listener,global.CustomEventEmitter.removeListener
('tabListClick', this.getLatestData);
5、在 Detail 页面如果购买了,就调用global.CustomEventEmitter.emit('tabListClick');
到这里用法已经就介绍完了,接下来简单介绍一下 EventEmitter 常用的 API:
- addListener(eventType: string, listener: Function, context: ?Object)
- eventType 为「事件名称」
- listener 是一个回调的 function
- context 表示 listener 调用时的上下文
- removeListener(eventType: String, listener)
- eventType 为「事件名称」
- listener 是一个回调的 function
- emit(eventType:string),传入一个「事件名称」
注意:eventType 要保持一致,并且区别大小写
其它 API 接口:
- constructor(subscriber: ?EventSubscriptionVendor)
- once(eventType: string, listener: Function, context: ?Object)
- removeAllListeners(eventType: ?string)
- removeCurrentListener()
- removeSubscription(subscription: EmitterSubscription)
- listeners(eventType: string)
B、Node.js 中的用法
- 在 Node.js 项目里的引用方式稍有不同 ,是
const EventEmitter = require('events');
- 在 Node.js 用了
on 做为 addListener 的别名
,也就是说 on('eventName') == addListener('eventName') - 同理,用了
off 做为 removeListener 的别名
,也就是说 off('eventName') == removeListener('eventName') - 调用时:emitter.emit('eventName');
示例代码如下:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('eventName', (a, b) => {
console.log(a, b, this);
// 打印: a b {}
});
myEmitter.emit('eventName', 'a', 'b');
这个例子的事件可以反复调用,只需调用:myEmitter.emit('eventName', 'a', 'b');
如果你有一个场景是只需要执行一次事件(比如:记录项目首次启动),Node.js 也帮我们考虑进去了,如官方代码所示:
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.once('event', () => {
console.log(++m);
});
myEmitter.emit('event');
// 打印: 1
myEmitter.emit('event');
// 不触发
Node.js 中 events 其它API:
- EventEmitter.defaultMaxListeners
- emitter.addListener(eventName, listener)
- emitter.emit(eventName[, ...args])
- emitter.eventNames()
- emitter.getMaxListeners()
- emitter.listenerCount(eventName)
- emitter.listeners(eventName)
- emitter.off(eventName, listener)
- emitter.on(eventName, listener)
- emitter.once(eventName, listener)
- emitter.prependListener(eventName, listener)
- emitter.prependOnceListener(eventName, listener)
- emitter.removeAllListeners([eventName])
- emitter.removeListener(eventName, listener)
- emitter.setMaxListeners(n)
- emitter.rawListeners(eventName)
网友评论