Skip to content

mitt

作者:Long Mo
字数统计:845 字
阅读时长:3 分钟

Tiny 200b functional event emitter / pubsub. Mitt 是为浏览器制作的,但适用于任何 JavaScript 运行时。它没有依赖关系,支持IE9+。

js
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)来实现多组件间的事件共享,可以遵循以下优雅的方式:

  1. 创建事件中心(Event Emitter): 首先,你需要有一个全局可用的事件中心,它通常是一个实现了发布订阅模式(Pub/Sub)的对象。这个对象提供注册监听器(subscribe)、注销监听器(unsubscribe)和发布事件(emit)的方法。可以使用现有的库如mitttiny-emitter ,或者自行实现一个简单的事件中心。

  2. 封装 useEventEmitter Hook: 创建一个名为useEventEmitter 的自定义Hook,它返回一个事件中心的实例。这个Hook应该只初始化一次事件中心,并且在整个应用生命周期内保持其唯一性。可以使用React的useRefuseMemo来确保这一点。

jsx
import { useRef, useEffect } from 'react';
import mitt from 'mitt';

const eventEmitter = useRef(mitt());

const useEventEmitter = () => {
	return eventEmitter.current;
};

export default useEventEmitter;
  1. 组件内使用: 在需要共享事件的各个组件中,导入并使用useEventEmitter Hook。

    发布事件: 当某个组件需要触发全局事件时,通过useEventEmitter获取事件中心实例,然后调用其emit方法,传入事件名和相关数据。

jsx
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 来注册和注销监听器。

jsx
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>
	);
}
  1. 注意事项
    • 事件命名:为事件选择明确且易于理解的名字,以减少命名冲突和提高代码可读性。
    • 数据序列化:如果事件携带的数据可能包含复杂对象,确保它们可以通过JSON.stringify进行序列化,以适应可能存在的跨上下文通信(如Web Workers、微前端等)。
    • 性能考虑 :大量使用事件可能会增加组件间的耦合度并影响性能。仅在必要时使用全局事件,对于紧密相关的组件,优先考虑使用React的contextuseReducer 或第三方状态管理库(如Redux、MobX)。

通过以上步骤,你可以在React应用中优雅地使用useEventEmitter来实现多组件间的事件共享,保持组件间的解耦,同时简化通信逻辑。

Contributors

Long Mo
文章作者:Long Mo
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Longmo Docs