Mitt:轻量级事件总线入门指南

262 阅读4分钟

一、为什么需要事件总线?

想象你在开发一个React应用,有这样一个场景:👇

  • 页面顶部有个搜索框组件
  • 页面底部有个商品列表组件
  • 当用户在搜索框输入关键词时,商品列表需要立即更新

如果这两个组件不是父子关系,用props传递数据会非常麻烦!这时候就需要事件总线(Event Bus)这个神奇的工具啦~

📌 通俗解释:事件总线就像一个对讲机,组件A(发送方)对着对讲机说话,组件B(接收方)只要也拿着对讲机(订阅了事件)就能听到,它们不需要知道对方在哪里。

二、认识Mitt:轻量级事件总线工具

Mitt是一个超级迷你的JavaScript库(只有200字节左右!),专门用来实现事件总线功能。它的名字取自"emit"(发射)的谐音。

Mitt的三大优势

  • 极简API:只有3个核心方法,5分钟就能学会
  • 超轻量:几乎不增加项目体积
  • 跨框架通用:React/Vue/Angular都能用

三、快速上手:5分钟安装使用Mitt

步骤1:安装Mitt

打开终端,在项目目录下运行:

npm install mitt
# 或者使用yarn
# yarn add mitt

步骤2:创建事件总线实例

在src目录下新建utils/eventBus.js文件:

// 引入mitt库
import mitt from 'mitt'

// 创建事件总线实例并导出
// 这就像创建了一个专属对讲机频道📻
const eventBus = mitt()

export default eventBus

四、核心API详解

Mitt只有3个核心方法,非常简单!

1. 订阅事件:on()

// 语法:eventBus.on('事件名称', 回调函数)

// 例子:订阅名为'keywordChange'的事件
eventBus.on('keywordChange', (data) => {
  console.log('收到新关键词:', data)
  // 这里写处理逻辑
})

2. 发布事件:emit()

// 语法:eventBus.emit('事件名称', 要传递的数据)

// 例子:发布'keywordChange'事件,传递搜索关键词
eventBus.emit('keywordChange', '夏季连衣裙')

3. 取消订阅:off()

// 语法:eventBus.off('事件名称', 要移除的回调函数)

// 先定义一个具名函数
const handleKeywordChange = (data) => {
  console.log('收到新关键词:', data)
}

// 订阅事件
eventBus.on('keywordChange', handleKeywordChange)

// 取消订阅(通常在组件卸载时)
eventBus.off('keywordChange', handleKeywordChange)

五、实战示例:搜索框与列表组件通信

让我们实现开头说的搜索功能,用两个简单组件演示:

组件1:搜索框(发布者)

import React, { useState } from 'react'
import eventBus from '../utils/eventBus'

const SearchBox = () => {
  const [keyword, setKeyword] = useState('')

  const handleInputChange = (e) => {
    const newKeyword = e.target.value
    setKeyword(newKeyword)
    
    // 当输入变化时,发布事件
    eventBus.emit('keywordChange', newKeyword)
  }

  return (
    <div style={{ margin: '20px' }}
      <input
        type="text"
        value={keyword}
        onChange={handleInputChange}
        placeholder="输入搜索关键词..."
        style={{ padding: '8px', width: '300px' }}
      />
    </div>
  )
}

export default SearchBox

组件2:商品列表(订阅者)

import React, { useState, useEffect } from 'react'
import eventBus from '../utils/eventBus'

const ProductList = () => {
  const [products, setProducts] = useState([])
  const [currentKeyword, setCurrentKeyword] = useState('')

  // 组件挂载时订阅事件
  useEffect(() => {
    // 定义事件处理函数
    const handleKeywordChange = (keyword) => {
      setCurrentKeyword(keyword)
      // 这里可以添加实际的搜索逻辑
      console.log('开始搜索:', keyword)
      // 模拟搜索结果
      setProducts([`${keyword}商品1`, `${keyword}商品2`])
    }

    // 订阅事件
    eventBus.on('keywordChange', handleKeywordChange)

    // 组件卸载时取消订阅
    return () => {
      eventBus.off('keywordChange', handleKeywordChange)
    }
  }, [])

  return (
    <div style={{ margin: '20px' }}
      <h3>搜索结果:{currentKeyword}</h3>
      <ul>
        {products.map((product, index) => (
          <li key={index}>{product}</li>
        ))}
      </ul>
    </div>
  )
}

export default ProductList

如何使用这两个组件

import React from 'react'
import SearchBox from './components/SearchBox'
import ProductList from './components/ProductList'

function App() {
  return (
    <div className="App">
      <h1>事件总线演示</h1>
      <SearchBox />
      <ProductList />
    </div>
  )
}

export default App

六、初学者必知的注意事项 ⚠

  1. 内存泄漏问题

    • 组件卸载时必须off()取消订阅
    • 忘记取消会导致组件已经消失但仍能接收事件
  2. 事件名称规范

    • 建议使用统一前缀,如user:logincart:update
    • 避免使用简单字符串如'change',容易冲突
  3. 数据格式统一

    • 建议始终传递对象格式数据,方便扩展:
    // 推荐
    eventBus.emit('user:login', { id: 1, name: '小明' })
    
    // 不推荐
    eventBus.emit('user:login', 1, '小明')
    

七、Mitt适用场景

适合用Mitt的场景

  • 简单的跨组件通信
  • 全局通知(如登录状态变化)
  • 非父子组件间的简单交互

不适合的场景

  • 复杂的状态管理(这时候应该用Redux/Vuex)
  • 需要追踪状态变化历史
  • 大型应用的核心业务逻辑

八、总结

Mitt就像一把小巧的瑞士军刀,虽然简单但在特定场景下非常实用。通过本文你已经学会:

  1. 事件总线解决了什么问题

  2. 如何安装和创建Mitt实例

  3. 三大核心API(on/emit/off)的使用

  4. 一个完整的跨组件通信示例

  5. 初学者需要注意的事项