
React应用中mitt库事件监听器重复触发问题详解及解决方案
本文分析了在React应用中使用mitt库进行组件间通信时,事件监听器重复触发的常见问题,并提供有效的解决方案。
问题描述:
使用mitt库构建的事件发射器(emitter),组件A通过emitter.emit('e1', data)发射事件,组件B通过emitter.on('e1', callback)监听事件。然而,点击组件A的按钮后,组件B的回调函数callback被执行多次,而非预期的一次。
示例代码:
emitter/index.ts:
import type { emitter } from 'mitt'
import mitt from 'mitt'
export default mitt() as emitter<any>组件A:
import { useEffect } from 'react'
import emitter from '../../emitter'
function Index() {
useEffect(() => {
console.log('组件A挂载')
}, [])
return (
<button onClick={() => {
console.log('按钮被点击');
emitter.emit('e1', { "name": "zhangsan" });
}}>A发送信息到B</button>
);
}
export default Index;组件B:
import { useEffect } from 'react'
import emitter from '../../emitter'
function Index() {
useEffect(() => {
console.log('组件B挂载');
emitter.on('e1', (e) => {
console.log('mitt test', e);
});
}, []);
return <div>BBB</div>;
}
export default Index;问题原因分析:
组件B在useEffect钩子函数中添加事件监听器,空依赖数组导致该函数在组件挂载后执行一次。关键问题在于:emitter.on('e1', callback)注册的监听器未在组件卸载时移除。每次组件B重新渲染(例如,由于其他状态变化),useEffect都会重新执行,再次注册相同的监听器,导致事件重复触发。
解决方案:
在useEffect的返回值中添加清理函数,在组件卸载前移除监听器:
import { useEffect } from 'react'
import emitter from '../../emitter'
function Index() {
useEffect(() => {
const unsubscribe = emitter.on('e1', (e) => {
console.log('mitt test', e);
});
return () => {
unsubscribe(); // 组件卸载时移除监听器
};
}, []);
return <div>BBB</div>;
}
export default Index;修改后的代码在组件卸载时调用unsubscribe()函数,移除已注册的事件监听器,有效避免重复触发。 这确保了每个组件生命周期内只注册一次监听器,解决了重复触发的问题。

