mitt
Tiny 200b functional event emitter / pubsub. Mitt 是为浏览器制作的,但适用于任何 JavaScript 运行时。它没有依赖关系,支持IE9+。
import mitt from 'mitt'
const emitter = mitt()
// listen to an event
emitter.on('foo', e => console.log('foo', e))
// listen to all events
emitter.on('*', (type, e) => console.log(type, e))
// fire an event
emitter.emit('foo', { a: 'b' })
// clearing all events
emitter.all.clear()
// working with handler references:
function onFoo() {
}
emitter.on('foo', onFoo) // listen
emitter.off('foo', onFoo) // unlisten
React中如何优雅的使用 useEventEmitter 进行多组件事件共享
在React中,使用useEventEmitter
(或类似的自定义Hook,如getMyEmitter
)来实现多组件间的事件共享,可以遵循以下优雅的方式:
创建事件中心(Event Emitter): 首先,你需要有一个全局可用的事件中心,它通常是一个实现了发布订阅模式(Pub/Sub)的对象。这个对象提供注册监听器(subscribe)、注销监听器(unsubscribe)和发布事件(emit)的方法。可以使用现有的库如
mitt
、tiny-emitter
,或者自行实现一个简单的事件中心。封装 useEventEmitter Hook: 创建一个名为
useEventEmitter
的自定义Hook,它返回一个事件中心的实例。这个Hook应该只初始化一次事件中心,并且在整个应用生命周期内保持其唯一性。可以使用React的useRef
或useMemo
来确保这一点。
import { useRef, useEffect } from 'react';
import mitt from 'mitt';
const eventEmitter = useRef(mitt());
const useEventEmitter = () => {
return eventEmitter.current;
};
export default useEventEmitter;
组件内使用: 在需要共享事件的各个组件中,导入并使用
useEventEmitter
Hook。发布事件: 当某个组件需要触发全局事件时,通过
useEventEmitter
获取事件中心实例,然后调用其emit
方法,传入事件名和相关数据。
import useEventEmitter from './useEventEmitter';
function PublisherComponent() {
const emitter = useEventEmitter();
const handleClick = () => {
const eventData = { message: 'Hello from Publisher!' };
emitter.emit('globalEvent', eventData);
};
return <button onClick={handleClick}>Publish Event</button>;
}
订阅事件: 在希望接收并响应全局事件的组件中,同样使用useEventEmitter
获取事件中心实例,然后调用其on
方法注册监听器。监听器是一个回调函数,当指定事件被触发时会被调用。为了确保组件卸载时能正确清理资源,使用useEffect
来注册和注销监听器。
import useEventEmitter from './useEventEmitter';
function SubscriberComponent() {
const emitter = useEventEmitter();
const [receivedData, setReceivedData] = useState(null);
useEffect(() => {
const handleGlobalEvent = (data) => {
setReceivedData(data);
};
// 注册监听器
emitter.on('globalEvent', handleGlobalEvent);
// 返回一个清理函数,用于在组件卸载时注销监听器
return () => {
emitter.off('globalEvent', handleGlobalEvent);
};
}, [emitter]);
return (
<div>
{receivedData ? (
<p>Received data from global event: {receivedData.message}</p>
) : (
<p>Waiting for event...</p>
)}
</div>
);
}
- 注意事项:
- 事件命名:为事件选择明确且易于理解的名字,以减少命名冲突和提高代码可读性。
- 数据序列化:如果事件携带的数据可能包含复杂对象,确保它们可以通过
JSON.stringify
进行序列化,以适应可能存在的跨上下文通信(如Web Workers、微前端等)。 - 性能考虑 :大量使用事件可能会增加组件间的耦合度并影响性能。仅在必要时使用全局事件,对于紧密相关的组件,优先考虑使用React的
context
、useReducer
或第三方状态管理库(如Redux、MobX)。
通过以上步骤,你可以在React应用中优雅地使用useEventEmitter
来实现多组件间的事件共享,保持组件间的解耦,同时简化通信逻辑。