🧳 我的 React Trip 之旅(last):UI 库的 Toast 太弱,我用 mitt 写了个会“飞”的通知

57 阅读2分钟

一行代码全局弹出,跨层级通信的秘密武器竟然是它?


🍞 开头:我想弹个通知,结果被 UI 库“绑架”了

react-vant 的 Toast 很好用,但只能显示“文字”或“加载中”。

可我想显示:

👤 3 条新消息
🔔 6 个提醒
✉ 9 封邮件

UI 库说:“不支持,自己写。”

我翻遍文档,发现要么用 Context(太重),要么层层传 props(太蠢)。

直到我遇见了 mitt ——一个只有 200 行代码的“事件总线”,轻得像一张纸。


🚌 mitt 是什么?一个“公交车站”

想象 mitt 是一个公交车站:

  • 任何组件都可以上车(emit 事件)
  • 任何组件也可以等车(on 监听事件)

比如,我在 ToastController.js 里设了个站:

// ToastController.js
import mitt from 'mitt';
export const toastEvents = mitt();

export function showToast(user = 0, bell = 0, mail = 0) {
  toastEvents.emit('show', { user, bell, mail }); // 发车!
}

然后,Toast 组件在车站等车:

// Toast.jsx
useEffect(() => {
  const show = (info) => {
    setData(info);
    setVisible(true);
    setTimeout(() => setVisible(false), 3000);
  };
  toastEvents.on('show', show); // 上车!
  return () => toastEvents.off('show', show); // 下车!
}, []);

🎯 使用起来有多爽?

在任意组件,比如 Home.jsx

import { showToast } from '@/components/Toast/ToastController';

<Button onClick={() => showToast(3, 6, 9)}>
  弹个通知!
</Button>

不需要 import Toast 组件,不需要传 props,不需要 context——
只要调用 showToast,通知就“从天而降”。


🎨 样式细节:让它看起来像“官方出品”

  • position: fixed + bottom: 120px(避开 TabBar)
  • animation: fadeIn(淡入动画)
  • 三角形箭头(用 border hack 实现)
  • z-index: 1000(确保不被遮挡)
.toastArrow {
  position: absolute;
  bottom: -12px;
  right: 32px;
  width: 0;
  height: 0;
  border-left: 12px solid transparent;
  border-right: 12px solid transparent;
  border-top: 12px solid #1890ff;
}

面试官问:“跨组件通信你怎么做的?”
我:“mitt 事件总线,轻量、解耦、一行调用。”


🎯 结尾:小工具,大智慧

这个 Toast 虽小,却体现了前端工程的核心思想:

  • 解耦:调用方和实现方完全无关
  • 复用:全站任意地方可用
  • 可控:自动消失、动画、样式统一

有时候,最好的架构,不是最复杂的,而是最合适的


🧭 最终章:我的 TripApp,不止是一个项目

从空文件夹,到像素级还原设计稿;
从 TabBar 高亮,到瀑布流滚动;
从防抖搜索,到 AI 聊天;
从自定义 Toast,到工程化规范……

我的 TripApp 或许永远不会上线 App Store,但它承载了我对前端的热爱、思考与坚持。

每一个组件,都是旅途中的一块路标;每一行代码,都是写给未来的自己的一封信

感谢你陪我走完这段 React Trip 之旅。
愿你的代码,也如旅途般精彩 🧳✨